Function f will have two integer parameters named x and y that are passed by value and it returns a single integer. Also in function f are two local variables a and b.
In f's prolog, need to allocate space needed by the function for return addresses, registers, parameters and local variables. Also need to initialize local parameter space and save the return address.
f: .data f_Return_addr: .word 0 # storage for return address f_Registers: .space 48 # storage for a and t registers f_x: .word 0 # parameter 1 f_y: .word 0 # parameter 2 f_a: .word 0 # local variable a f_b: .word 0 # local variable b .text sw $ra,f_Return_addr sw $a0,f_x sw $a1,f_yIn the body of the function, x,y,a and b are accesses as f_x, f_y, f_a, and f_b.
In the epilog, need to make sure the return value (if any) is in a known place, then load the stored return address into a register so it can be used to return control back to the call point. Be careful to include an epilog even if there is no return statement in the function. I automatically add this code once I'm done parsing a function (even it the code is unreachable).
move $v0,$t0 # assumes the return value is in $t0 lw $t0,f_Return_addr jr $t0
At the call site, you need to store any $t registers that are in use - you can also store them all if that makes your life easier. Here, I'm assuming that global variables a and b have the names global_a and global_b respectively (allocated elsewhere).
sw $t0, FN1_Registers sw $t1, FN1_Registers+4 ... sw $a0, FN1_Registers+32 sw $a1, FN1_Registers+36 lw $t0,global_a move $a0, $t0 lw $t2,global_b move $a1, $t2 jal f lw $t0, FN1_Registers lw $t1, FN1_Registers+4 ... lw $a0, FN1_Registers+32 lw $a1, FN1_Registers+36 move $t2,$v0
offset(s) Data size 0 return address 4 4 old frame ptr 4 (dynamic link) 8 t registers 32 40 a registers 16 56 local var 1 4 60 local var 2 4 64 local var 3 4 . . .The stack pointer appears to be set correctly to point at the 'top' of the stack when SPIM execution starts. The frame pointer always points to the last word of the current activation. I maintain this setup in the code below, although it is not clear whether I need maintain the frame pointer or not.
In the code below, the 'push' assumes that the overall activation record size is 104, which corresponds to space for 12 local variables in the activation. Obviously, different functions can have different size activations.
sw $ra,0($sp) # save return address sw $a0,56($sp) # parameter x sw $a1,60($sp) # parameter yNOTE: local variables a and b will be stored at offsets 64 and 68 respectively.
move $v0,$t1 lw $t1,0($sp) jr $t1
sw $t0,8($sp) # saving registers sw $t1,12($sp) . . . sw $a0,40($sp) sw $a1,44($sp) sw $a2,48($sp) sw $a3,52($sp) lw $t0,a_global # get actual parameters move $a0,$t0 lw $t0,b_global move $a1,$t0 sw $fp,4($sp) #save dynamic ptr subu $sp,$sp,104 # update stack pointer by activation size addiu $fp,$sp,100 # set frame ptr (points to end of act) jal outputnums addiu $sp,$sp,104 # reset sp to old value lw $fp,4($sp) # reset frame point from activation lw $t0,8($sp) # restoring registers lw $t1,12($sp) . . . lw $a0,40($sp) lw $a1,44($sp) lw $a2,48($sp)