Discussion 5

9/24/02 Tue

  1. Procedure calls in MIPS assembly
  2. Bitwise operations

Procedure calls in MIPS assembly

How can I call a procedure?

1) Copy the arguments (registers $a0, $a1, $a2, and $a3)

2) Copy the return address onto the return address register ($ra) and jump to the procedure.

3) Inside the procedure

4) Access the return value (registers $v0, $v1)

How can I return a value from the procedure?

1) Copy the result onto the return value registers $v0 and $v1

2) Jump to the return address using the return address register ($ra)

Example

main() {
	int i,j,k,m;	/* $s0, $s1, $s2, $s3 */
	...
	i = mult(j,k); ...
	m = mult(i,i); ...
}
/* really dumb mult function */
int mult (int mcand, int mlier){
	int product;
	product = 0;
	while (mlier > 0) {
		product = product + mcand;
		mlier = mlier -1;
	}
	return product;
}
-------------------------------------
__start:
	add $a0, $s1, $zero
	add $a1, $s2, $zero
	jal mult
	add $s0, $v0, $zero
	add $a0, $s0, $zero
	add $a1, $s0, $zero
	jal mult
	add $s3, $v0, $zero
	done
mult:
	add $t0, $zero, $zero
	...
	jr $ra

Is this all about MIPS procedure call?

No. The example above is an extremely simple one. The caller (main) doesn't have a procedure which called it. And the callee (mult) doesn't make any procedure calls. In general, a procedure can be called from a procedure (it is considered the callee in this case) and it can also call other procedures (it is considered the caller in this case). 

No. The example above is extremely simple. main just ends the program without returning to another procedure and the mult doesn't make any procedure calls. In general, a procedure can be called from another procedure and can call other procedures. In that case, we need to save registers to prevent the registers from being hampered a procedure call.

Register conventions:

Registers can be categorized as follows.

Registers Purposes Save/Restore Description
$sp Stack pointer Callee Needs to be grown when some registers need to be saved/restored.
$s0 - $s7 Local variables. Callee Need to be saved when the procedure modifies them.
$ra Return address Caller Need to be saved when the procedure calls another procedure
$a0 - $a3 Arguments Caller Need to be saved if they are used after a procedure call.
$v0, $v1 Return values Caller
$t0 - $t9 Temporary variables. Caller

General procedure call conventions.

1) Grow the stack by subtracting the stack pointer ($sp) as much as the procedure needs (frame size).

    Save the registers the procedure should not change ($s0 - $s7 and $ra) using store instruction (sw).

 

2) Do the operations (return values are copied onto $v0 and $v1).

This can be repeated.

3) Copy arguments onto registers $a0, $a1, $a2 and $a3.

    Save the registers ($t0 - $t9, $a0 - $a3) the procedure wants to preserve after call using store instruction.

    A procedure call

    Restore the registers ($t0 - $t9, $a0 - $a3) if necessary.

4) Restore the registers ($s0-$s7, $ra).

    Shrink the stack by adding the stack pointer with the frame size.

    Return using return address register ($ra).

 

Example

int fib(int n) {
	if(n == 0) { return 1; }
	if(n == 1) { return 1; }
	return (fib(n - 1) + fib(n - 2));
}

Is this called by another procedure?

    Yes.

    It needs to save the local variables it modifies.

    It needs to grow stack frame by subtracting stack pointer.

Does this call other procedures?

    Yes.

    It needs to copy arguments and make a procedure call. 

    If necessary it needs to save return address, arguments or temporary variables.

Apply the general case conventions.

fib:
addi $sp, $sp, -12
sw $ra, 8($sp)
sw $s0, 4($sp)
Step (1)
Grows stack and saves the return address ($ra) and a local variable ($s0) which will be modified within the procedure.
addi $v0, $zero, 1
beq $a0, $zero, fin
addi $t0, $zero, 1
beq $a0, $t0, fin
Step (2)
addi $a0, $a0, -1
sw $a0, 0($sp)
jal fib
lw $a0, 0($sp)
Step (3)
Copy an arguement onto $a0. Saves and restores $a0 across the procedure call to reuse $a0 later.
addi $a0, $a0, -1
add $s0, $v0, $zero
jal fib
Step (3)
Copy an arguement onto $a0. Doesn't need to save arguments because the arguments are not needed after the call.
add $v0, $v0, $s0 Step (2)
fin:
lw $s0, 4($sp)
lw $ra, 8($sp)
addi $sp, $sp, 12
jr $ra
Step (4)
Restore the return address ($ra) and a local variable ($s0).
Jump to the return address.

Example

int sum(int n) {
	if(n == 1) { return 1; }
	return (n + sum(n - 1));
}

Is this called by another function? Yes. It needs to save the return address and the local variables.

Does it call other function? Yes, but it calls a procedure only once. Thus it doesn't need to save and restore arguments across the call.

sum:
addi $sp, $sp, -8
sw $ra, 4($sp)
sw $s0, 0($sp)
addi $v0, $zero, 1
addi $t0, $zero, 1
beq $a0, $t0, fin
add $s0, $a0, $zero
add $a0, $a0, -1
jal sum
add $v0, $v0, $s0
fin:
lw $ra, 4($sp)
lw $s0, 0($sp)
addi $sp, $sp, 8

Bitwise operations

What is bitwise operations?

The basic data operations in MIPS are done in 32-bit units. Bitwise operations allow us to access the data in smaller units.

AND (and, andi) operation

AND operation takes two operands (either two registers or one register and immediate value) and  does logical AND operation for each bit. The Logical AND operation returns 1 when both bits are 1. Otherwise the operation returns 0.

AND operation is used for masking. If we want to take the rightmost byte from 4-byte word, we can AND a register with 0x000000ff.

addi $t0, $zero, $0xff    # set $t0 as 0x000000ff
andi $t1, $t1, $t0        # and $t1 with 0x000000ff

The resulting value in register $t1 contains the rightmost byte of the original value.

AND operation is also used to selectively clear a bit in a register.

OR (or, ori) operation

OR operation takes two operands (either two registers or one register and immediate value) and  does logical OR operation for each bit. The Logical OR operation returns 1 when either of the bits are 1. Otherwise the operation returns 0.

OR operation is used to selectively set a bit in a register.

Shift (sll, srl, sra) operation

Logical shift left (sll) operation shift the bits in a register to the left by shift amount and fills rightmost bits with zeros.

Logical shift right (sll) operation shift the bits in a register to the right by shift amount and fills leftmost bits with zeros. 

Arithmetic shift right (sll) operation shift the bits in a register to the right by shift amount and fills leftmost bits with sign extending. 

Example

MIPS has a coprocessor 0 to manage the processor states. Status register ($12) of coprocessor 0 allows us enable or disable interrupts.

  15             8   5 4 3 2 1 0
                               
  Interrupt mask   Old Previous Current
  Kernel
/user
Int 
enable
Kernel
/user
Int 
enable
Kernel
/user
Int 
enable

To check whether the current interrupt is enabled,

mfc0    $k0, $12       # copy the status register to $k0

andi    $k0, $k0, 0x0001    # $k0 is not zero if the current interrupt is enabled.

To set a bit in the status register.

ori    $k0, $k0, 0x0001

mtc0    $k0, $12

To clear a bit in the status register.

andi    $k0, $k0, 0xfffe

mtc0    $k0, $12

Back to Top

Revised: 09/24/02 .