Subroutines part 3
We need to talk about how subroutines communicate with their callers in the MIPS world.
When a subroutine is called, it is typically sent some actual parameters by its caller.
The values of these parameters will affect the execution of the subroutine.
A function will also return a value to its caller. This page is about how that communication is done.
- Registers $a0, $a1, $a2, and $a3 are reserved for carrying parameters to the subroutine.
- This means that, before a subroutine can be called,
the correct values must be placed into these registers.
- If a subroutine has one parameter, it goes in $a0.
- If it has two parameters, the first goes in $a0, and the second goes in $a1.
- Similarly for three and four parameters.
- If there are more than four parameters, the stack is used for the others,
but don't worry about that. It won't happen in this course.
- Registers $v0 and $v1 are reserved for carrying a function's returned value back to the caller.
- If the returned value is 32 bits, it goes in $v0.
- If the returned value is 64 bits, e.g. a double, it is split between $v0 and $v1.
A typical scenario for the whole thing would therefore be like this:
- copy the parameters into the $a registers; this would likely use move and lw instructions
- call the subroutine; this will always be "jal subroutine-name"
- copy the returned value from $v0 to its proper place; this would usually be a move or a sw
Here's an example: we need to call doubleit, a function that returns twice the value in its parameter.
You can paste this code into MARS and run it. You can also single-step through it and watch the values
in the registers and program counter change.
# call doubleit to double the value of x and put the doubled value into two-x; in C, it would look like this:
# two-x = doubleit(x);
.include "macros.asm" # we need this because quit is a macro
x: .word 15
two-x: .word 0
main: lw $a0 x # parameter
sw $v0 two-x # returned value
# this function must put twice its parameter (in $a0) into its returned-value register ($v0)
doubleit: add $v0 $a0 $a0 # $v0 = 2 * $a0