Show understanding of and be able to use different modes of addressing

4.2 Assembly Language – Addressing Modes (Cambridge AS & A Level 9618)

Learning outcomes (linked to the syllabus)

  • AO1 – Knowledge: Demonstrate understanding of the relationship between assembly language symbols and the underlying hardware addressing modes.
  • AO2 – Application: Analyse and trace programs, showing how different addressing modes affect the fetch‑execute cycle, memory‑access cost and overall performance.

Why addressing modes matter

  • They determine how many memory accesses a single instruction requires.
  • More complex modes (e.g. based‑indexed with displacement) need extra address‑generation steps, increasing cycle count.
  • Choosing the most suitable mode reduces program size, improves speed and is essential for the “trace‑the‑program” questions in Paper 1.

Cambridge syllabus list of addressing modes (quick reference)

Mode (syllabus name)Syllabus syntaxCommon hardware nameTypical instruction (9618)Typical use
Immediate#nImmediateLDM R0, #nLoad a constant, set flags
Direct (absolute)<address>DirectLDD R1, <addr>Fixed variables, I/O ports
Register‑indirect(R)Register IndirectLDD R2, (R3)Pointer dereferencing, stack access
Indexed (base‑indexed)<address>(R)IndexedLDX R4, <addr>(R5)Array element access
Based‑indexed with displacement<address>(R1+R2*scale+disp)Based‑Indexed + DisplacementLDX R6, <addr>(R7+R8*4+8)Structure fields, multi‑dimensional arrays
PC‑relative (branch)labelRelativeBR labelLoops, conditional branches, function calls
Stack‑relativePUSH / POPStack‑relativePUSH R0 / POP R1Procedure call/return, local variables

Notation‑to‑mode cheat‑sheet (exam‑style)

Syllabus symbolMeaningHardware modeExample instruction
#nLiteral constant nImmediateLDM R0, #5
<addr>Absolute memory addressDirectLDD R1, <0x3C00>
(R)Address stored in register RRegister‑indirectLDD R2, (R3)
<addr>(R)Base address + contents of R (no scaling)IndexedLDX R4, <0x2000>(R5)
<addr>(R1+R2*scale+disp)Base + (index × scale) + displacementBased‑Indexed + DisplacementLDX R6, <0x1000>(R7+R8*4+8)
labelSigned offset from the current PCPC‑relativeBR label
PUSH / POPImplicit use of the stack pointer (SP)Stack‑relativePUSH R0 / POP R1

Syllabus‑specific quirk

The 9618 specification assumes a single accumulator register (ACC) for arithmetic results, but the instruction set also provides a small set of general‑purpose registers (R0‑R9) for address manipulation. All examples below respect the “one‑accumulator” rule for arithmetic, using the GP registers only for addressing.

Detailed description of each addressing mode

1. Immediate

  • The operand is encoded directly in the instruction word.
  • No extra memory fetch is required after the instruction fetch.
  • Typical use: loading constants, initialising flags.

2. Direct (absolute)

  • The instruction contains a full 16‑bit address.
  • CPU performs a second memory read to fetch the operand from that address.
  • Best for global/static variables whose address is known at assembly time.

3. Register‑indirect

  • The address is held in a register; the register itself is not altered.
  • Common for pointer variables and stack operations (the stack pointer is a special register SP).

4. Indexed (base‑indexed)

  • Effective address = Base address (constant) + contents of index register.
  • When accessing arrays, the index register is usually multiplied by the element size (the scale factor).

5. Based‑indexed with displacement

  • EA = Base + (Index × Scale) + Displacement.
  • Allows simultaneous use of a pointer (base), an index (loop counter) and a fixed field offset.
  • Ideal for structure fields or multi‑dimensional arrays.

6. PC‑relative (branch)

  • The operand is a signed offset added to the current Program Counter (PC).
  • Only one memory access (the branch instruction itself).
  • Used for loops, conditional branches and sub‑routine calls (via CALL which is PC‑relative).

7. Stack‑relative (PUSH / POP)

  • Implicitly uses the stack pointer (SP) which is automatically incremented/decremented.
  • Two memory accesses: one for the operand, one for updating SP.
  • Fundamental for procedure call/return protocols.

Two‑pass assembler – concrete example (syllabus style)

Consider the following 5‑line source program:

;--- Source -------------------------------------------------

START: LDM R0, #10 ; load constant

LDD R1, (R2) ; load via pointer

BR END ; skip the next line

LDD R1, <VALUE> ; never executed

END: NOP

VALUE: .WORD 0x55AA

Pass 1 – Symbol table construction

LabelAddress (hex)
START0x0000
END0x0014
VALUE0x0016

Pass 2 – Encoding (illustrative 16‑bit machine code)

AddressMachine code (binary)Explanation
0x00000010 0000 0000 1010LDM R0, #10 (opcode 0010, immediate 1010)
0x00020101 0001 0010 0011LDD R1, (R2) (opcode 0101, reg 0010 = R2)
0x00041000 0000 0000 1010BR END (offset +10 bytes = 0x000A)
0x00060101 0001 0000 0110LDD R1, <VALUE> (direct address 0x0016)
0x00080000 0000 0000 0000NOP
0x00160101 0101 1010 1010Data word 0x55AA

The symbol table from Pass 1 supplies the concrete address for END and VALUE during Pass 2, allowing the assembler to encode the correct offsets and absolute addresses.

Calculating Effective Addresses (EA)

For indexed and based‑indexed modes the general formula is:

EA = Base + (Index × Scale) + Displacement

  • Base – constant supplied in the instruction (often the start address of an array or structure).
  • Index – contents of an index register (e.g. loop counter).
  • Scale – 1, 2, 4 or 8, matching the size of the data element.
  • Displacement – signed constant added by the instruction (field offset, array stride, etc.).

Example 1 – Array element

Given int a[10]; at address 0x1000 and the index i in R1:

LDX R0, <0x1000>(R1*4) ; scale = 4 (size of int)

EA = 0x1000 + (i × 4). The element a[i] is loaded into R0.

Example 2 – Structure field

struct Point { int x; int y; }; // offsets: x=0, y=4

; address of variable p is in R3

LDX R4, (R3+4) ; load p.y

Here Base = contents of R3, Index = 0, Scale = 1, Displacement = 4.

Bit‑manipulation (syllabus 4.3) – essential for AO1 & AO2

OperationAssembly mnemonic (9618)Typical use
Logical left shiftLSL Rdst, Rsrc, #nMultiply by 2ⁿ, move bits into higher positions.
Logical right shiftLSR Rdst, Rsrc, #nUnsigned division by 2ⁿ, clear high bits.
Arithmetic right shiftASR Rdst, Rsrc, #nSigned division preserving sign bit.
Bitwise AND (masking)AND Rdst, Rsrc, #maskExtract specific bits.
Bitwise ORORR Rdst, Rsrc, #maskSet specific bits.
Bitwise XOREOR Rdst, Rsrc, #maskToggle bits.
Test‑and‑setTSB Rdst, Rsrc, #bitSet a single bit and record previous value.
Clear‑bitAND Rdst, Rsrc, #~bitForce a bit to 0.

Example – Extract the low 4 bits of a byte stored at address 0x3000:

LDD R0, <0x3000> ; load byte

AND R0, R0, #0x0F ; mask with 0000 1111

Performance note – effect on the fetch‑execute (F‑E) cycle

ModeMemory accesses per instructionTypical cycle count (illustrative)
Immediate1 (instruction only)2‑3 cycles
Direct2 (instruction + operand fetch)3‑4 cycles
Register‑indirect / Indexed2 (instruction + EA‑derived fetch)3‑5 cycles (EA calculation)
Based‑indexed with displacement2 (plus internal arithmetic)4‑6 cycles
PC‑relative (branch)1 (offset encoded)2‑3 cycles (pipeline flush if taken)
Stack‑relative (PUSH/POP)2 (access SP and operand)3‑4 cycles

When answering exam questions, always comment on the extra memory accesses or arithmetic steps introduced by the chosen mode.

Cost‑analysis exercise (AO2)

Two equivalent code fragments are given. For each fragment state the total number of memory accesses and the estimated cycle count (use the table above).

Fragment A:

LDD R0, <ARRAY> ; load first element (direct)

LDX R1, <ARRAY>(R2*4) ; load ARRAY[i] (based‑indexed)

Fragment B:

LDD R0, (R3) ; R3 holds address of ARRAY[0] (register‑indirect)

ADD R4, R2, #4 ; R4 = i*4

ADD R4, R3, R4 ; R4 = base + offset

LDD R1, (R4) ; load ARRAY[i] via indirect

Answer (teacher guide)

  • Fragment A: 2 memory accesses (direct + based‑indexed) → ≈ 4‑5 cycles.
  • Fragment B: 4 memory accesses (indirect load + three arithmetic instructions each requiring a fetch) → ≈ 7‑9 cycles.
  • Conclusion: Fragment A is faster and uses fewer memory accesses.

Trace‑the‑Program exercise (AO2 – sample)

;--- Data -------------------------------------------------

DATA1: .WORD 0x1234

DATA2: .WORD 0xABCD

ARRAY: .WORD 5, 10, 15, 20 ; base = 0x2000

;--- Registers before execution ----------------------------

R0 = 0x0000 ; result register

R1 = 0x0002 ; index = 2

R2 = <DATA1> ; 0x1000

R3 = <ARRAY> ; 0x2000

;--- Instructions -----------------------------------------

LDD R0, (R2) ; 1

LDX R0, <0x2000>(R1*2) ; 2

LDM R0, #0x55 ; 3

BR END ; 4

LDD R0, <DATA2> ; 5 (skipped)

END: NOP

Answer key

  1. EA = contents of R2 = 0x1000 → R0 = 0x1234
  2. EA = 0x2000 + (2 × 2) = 0x2004 → R0 = 15 (third element of ARRAY)
  3. R0 = 0x55
  4. Branch taken → instruction 5 is not executed.

Quick checklist – selecting the appropriate mode

  1. Constant value? – Use #n (Immediate).
  2. Fixed address known at assembly time? – Use Direct (<addr>).
  3. Address stored in a register? – Use Register‑indirect ((R)).
  4. Array/table lookup where the index is in a register? – Use Indexed (<addr>(R)) with appropriate scale.
  5. Structure field with known offset? – Use Based‑indexed with displacement ((R+disp) or full form).
  6. Branch within the same routine? – Use PC‑relative (label).
  7. Procedure call/return or local stack variables? – Use Stack‑relative (PUSH / POP).

Common pitfalls

  • Forgetting to multiply the index by the element size when using indexed modes.
  • Using a signed displacement where the architecture expects an unsigned offset (or vice‑versa) in PC‑relative branches.
  • Confusing a register that holds data with one that holds an address – leads to indirect vs. direct mistakes.
  • Ignoring alignment requirements; many 32‑bit CPUs fault on mis‑aligned word accesses.
  • Assuming the accumulator can be used for address calculations – the ACC is for arithmetic results only; address generation must use GP registers.

Summary

  • Addressing modes translate high‑level variable references into concrete memory accesses.
  • Know the syllabus symbols (#n, <address>, LDM, LDD, LDX) and map them to the correct hardware mode.
  • Two‑pass assembly: Pass 1 builds the symbol table; Pass 2 encodes the chosen mode into the opcode.
  • Performance depends on the number of memory accesses and on extra EA arithmetic – always comment on this in AO2 questions.
  • Practice by converting short C fragments into the exact 9618 instruction set, tracing the program, and comparing alternative addressing‑mode choices.