Cambridge 9618 · International A Level Computer Science · ~14 min read
Notes
Video
Slides
Quiz
Worksheet
Subroutines in Assembly Language
A subroutine (also called a procedure or function) is a named block of code that can be called from multiple points in a program. Using subroutines avoids code duplication and makes programs easier to read and maintain.
In Cambridge 9618 assembly language, subroutines are implemented using:
CALL label — call the subroutine at the given label; the return address is saved automatically
RET — return from the subroutine back to the instruction after the CALL
How CALL Works
When CALL SUBR is executed:
The current value of PC (the return address — address of the next instruction after CALL) is automatically pushed onto the stack
The PC is set to the address of SUBR — execution jumps to the subroutine
When RET is executed:
The return address is popped from the stack into the PC
Execution continues from where the CALL was made
The Stack
The stack is a region of memory that operates on a Last In, First Out (LIFO) basis. The Stack Pointer (SP) register keeps track of the top of the stack.
PUSH: decrements SP, then writes data to the location pointed to by SP
POP: reads data from the location pointed to by SP, then increments SP
Stack during subroutine call (stack grows downward):
Subroutines can call other subroutines. The stack handles multiple return addresses automatically — each CALL pushes a new return address, and each RET pops the most recent one (LIFO). This is why a stack is the ideal data structure for managing subroutine calls.
Complete Example: Subroutine Call
; MainLDM#5; ACC = 5
CALLDOUBLE; Call subroutine — pushes return addr to stack, jumps to DOUBLE
STORESULT; Store doubled value (returned in ACC)
END; Halt
; Subroutine
DOUBLE:ADDACC; Wait — wrong approach; we use the result in the register
LSL#1; Shift ACC left by 1 = multiply by 2 (doubling ACC)
RET; Return — pops return address from stack into PC
RESULT:0; Data location
Using PUSH and POP to Preserve Registers
If a subroutine modifies the ACC or other registers, the original values in those registers (needed by the calling program) are lost. To preserve register values across a subroutine call:
PUSH ACC at the start of the subroutine to save ACC to the stack
Use ACC for subroutine operations
POP ACC at the end of the subroutine to restore the original value before returning
This is known as a callee-saved (subroutine saves and restores) convention.
Parameter Passing via the Stack
Parameters can be passed to subroutines by pushing them onto the stack before the CALL. The subroutine then pops them off the stack to read the values. Return values can also be passed back via the stack (push before RET, pop after CALL) or returned in the ACC.
Summary Table
Instruction
Effect
CALL label
Push PC (return address) to stack; jump to label
RET
Pop return address from stack into PC; resume after CALL
PUSH ACC
Decrement SP; write ACC to Mem[SP]
POP ACC
Read Mem[SP] into ACC; increment SP
Exam tip: Cambridge questions often ask you to describe what happens to the stack during CALL and RET. Key points: CALL pushes the return address (the address of the instruction AFTER the CALL) onto the stack; RET pops it off. The stack uses LIFO — this allows nested subroutine calls to work correctly because each CALL pushes a new return address on top.
⚠️ Common Mistakes
Saying CALL saves the address of the CALL instruction itself — CALL saves the address of the NEXT instruction after CALL (so execution resumes there after RET)
Confusing the stack pointer direction — conventionally the stack grows downward (SP decrements on PUSH, increments on POP)
Not understanding that RET must match CALL — every CALL needs a RET at the end of the subroutine
Forgetting to POP in reverse order — if you push ACC then IX, you must pop IX then ACC (LIFO)
✅ Notes completed!
▶
Video coming soon
Click slide or press arrow keys to navigate
Worksheet — 1.4.1 Subroutines and the Stack
8 questions · instantly marked · Cambridge 9618 standard
Q1Explain what a subroutine is and give two benefits of using subroutines in assembly programs.[3]
✅ Mark scheme
Mark scheme
A subroutine is a named block of code that can be called from multiple points in a program [1]; benefits: avoids code duplication — write once, call many times [1]; makes programs easier to read, maintain and debug [1].
Q2Describe exactly what happens to the stack and the Program Counter when CALL SUBR is executed.[3]
✅ Mark scheme
Mark scheme
The address of the NEXT instruction after CALL (the return address) is pushed onto the stack [1]; the SP is decremented [1]; the PC is set to the address of SUBR — execution jumps to the subroutine [1].
Q3Describe what happens when RET is executed.[2]
✅ Mark scheme
Mark scheme
The return address is popped from the top of the stack [1]; the SP is incremented; this value is loaded into the PC so execution continues with the instruction that follows the CALL in the main program [1].
Q4Why is the stack (LIFO structure) ideal for managing subroutine return addresses, especially when subroutines call other subroutines?[3]
✅ Mark scheme
Mark scheme
Each CALL pushes a new return address on top of the previous one [1]; when RET is executed, it pops the most recently pushed address — returning to the most recently called subroutine's caller [1]; this LIFO order correctly mirrors the nesting of subroutine calls so the program always returns to the right place [1].
Q5Explain why a subroutine might need to PUSH ACC at the start and POP ACC at the end. What problem does this solve?[3]
✅ Mark scheme
Mark scheme
If the subroutine uses ACC for its own operations, the original value in ACC (from the calling program) is overwritten [1]; PUSHing ACC at the start saves the original value to the stack; POPping it at the end restores it before returning [1]; this ensures the calling program's register state is preserved — it sees the same register values before and after the CALL [1].
Q6State the effect of PUSH and POP on the Stack Pointer (SP).[2]
✅ Mark scheme
Mark scheme
PUSH: SP is decremented (stack grows downward); data is written to the new top of stack [1]; POP: data is read from the current top of stack; SP is incremented [1].
Q7A subroutine PUSHes both ACC and IX at the start. In what order must they be POPped at the end?[2]
✅ Mark scheme
Mark scheme
They must be POPped in reverse order to how they were pushed [1]; if ACC was pushed first then IX, then POP IX first, then POP ACC — because the stack is LIFO: last pushed (IX) must come off first [1].
Q8Write a short assembly subroutine called HALVE that divides the value in ACC by 2 using LSR, then returns.[3]
✅ Mark scheme
Mark scheme
HALVE: LSR #1 [1] (shift right 1 bit = divide by 2); RET [1]; label HALVE at start [1]. Accept with PUSH/POP if subroutine preserves registers.
Topic Quiz
Question 1 of 15
You scored
out of 15
Card 1 of 8
Click to reveal definition
🎉
All cards reviewed!
Term
Definition
🎯
Mini Test — 1.4.1 Subroutines & Stack
10 questions · 10 marks · 10 minutes
⏱ 10:00
10 marks
Section A — Multiple Choice [5 marks]
Q1What does CALL SUBR push onto the stack?
Q2The stack operates on which principle?
Q3What does RET do?
Q4PUSH ACC causes the Stack Pointer to:
Q5A subroutine pushes ACC, then IX. In what order must it pop them before RET?
Section B — Short Answer [5 marks]
Q6Explain why the stack pointer decrements on PUSH and increments on POP.
Mark schemeThe stack grows downward in memory [1]; PUSH adds data — SP decrements to point to the new free location, then data is written; POP reads data at SP then increments SP to free that location [1].
Q7State two benefits of using subroutines in an assembly language program.
Mark schemeAvoids code duplication [1]; makes the program easier to read/maintain/test [1]. Also accept: allows the same code to be reused from multiple points in the program.
Q8What value does CALL push onto the stack? Why is it this particular value?
Mark schemeCALL pushes the address of the instruction immediately AFTER the CALL instruction (the return address) [1]; this is so that when RET pops this value into PC, execution resumes correctly from the next instruction in the main program [1].
Q9Explain why nested subroutine calls work correctly when managed by a stack.
Mark schemeEach CALL pushes a new return address on top of any existing ones [1]; each RET pops only the most recent (top) address — returning to the immediately calling routine; the LIFO order ensures each routine returns to the correct caller [1].
Q10Write a subroutine called TRIPLE that triples the value in ACC (multiply by 3) using assembly instructions, then returns.
Mark schemeTRIPLE: PUSH ACC [stores copy]; STO TEMP; LDD TEMP; ADD TEMP; ADD TEMP; RET — OR: TRIPLE: STO TEMP; LDD TEMP; ADD TEMP; ADD TEMP; ADD TEMP; RET [Award 1 for label, 1 for correct logic tripling ACC, 1 for RET]. Multiple valid approaches accepted.