Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

MIPS_primery_zadach / dandamudi05gtr guide risc processors programmers engineers

.pdf
Скачиваний:
77
Добавлен:
11.05.2015
Размер:
1.39 Mб
Скачать

186

Guide to RISC Processors

root_type = roots (a, b, c, &root1, &root2);

In summary, procedures receive a list of parameters, which may be passed either by the call-by-value or by the call-by-reference mechanism. If more than one result is to be returned by a called procedure, the call-by-reference parameter-passing mechanism should be used.

Procedure Invocation

MIPS provides two instructions to support procedures: jal and jr. The jal instruction is used for calling a procedure and jr is used to return from a procedure. In this section, we discuss the jal instruction. The jr instruction is discussed in the next section.

The jal (jump and link) instruction

jal proc_name

transfers control to proc_name just as a jump instruction does. Because we need the return address to return from the called procedure, it also stores the address of the instruction following the delayed slot instruction in the $ra register. Here are the actions taken in invoking a procedure using the jal instruction:

$ra = PC + 8

PC = PC[31:28] || offset<<2

Notice that $ra (i.e., $31) is loaded with PC+8, not PC+4. This is because of the delayed slot instruction (see our discussion on page 25). Thus the control returns to the instruction following the delayed slot instruction.

This instruction uses the J-type instruction encoding shown in Figure 4.2 on page 52. As you can see from this figure, it uses 26 bits to specify the offset. The target address is computed as follows. The 26-bit offset specified in the instruction is shifted left by two bit positions because of the 32-bit alignment. This gives us 28 bits and the remaining 4 bits are taken from the PC. Before the control is transferred, the delayed branch instruction is executed.

SPIM note

Because SPIM simulates the MIPS R2000 processor, it does not

simulate the delayed branch. Thus, it performs $ra = PC + 4.

 

 

 

An Example

To understand the procedure invocation mechanism, let’s look at the program fragment, obtained from SPIM, shown in Figure 11.1. This code consists of three procedures: main, avg, and sum. The first column gives the address of each instruction (the 0x prefix

Chapter 11 Procedures and the Stack

187

address

machine code

 

 

; main:

 

 

. . .

 

[0x0040004c]

0x0c100022 jal 0x00400088 [sum] ; 37: jal

sum

 

. . .

 

 

; end of main procedure

 

;****************************************************************

 

 

;

sum:

 

 

 

[0x00400088]

0x34020000

ori $2, $0, 0

;

60: li

$v0,0

[0x0040008c]

0x0c10002c

jal 0x004000b0 [avg] ;

61: jal

avg

 

 

 

. . .

 

 

 

 

 

;

end of sum procedure

 

 

;****************************************************************

 

 

; avg:

 

 

 

[0x004000b0]

0x00044021

addu $8, $0,

$4

;

76: move $t0,$a0

 

 

. . .

 

 

 

[0x004000c0]

0x0c100022

jal 0x00400088 [sum] ;

80: jal sum

 

 

. . .

 

 

 

 

 

; end of avg

procedure

 

;****************************************************************

Figure 11.1 Sample code to explain procedure calls

indicates that the address in hex). The machine code generated is given in the second column. The third column gives the assembler translation of the source instruction given in the fourth column. For example, li $v0,0 is translated as ori $2,$0,0.

The procedure call instruction in the main procedure

jal sum

is encoded as 0x0c100022. The most significant 6 bits represent the opcode and the remaining 26 bits give the offset as shown below:

Opcode

Offset

0000 11 00 0001 0000 0000 0000 0010 0010

Multiplying this offset by four (equivalent to left-shifting by two bit positions), we get the 28-bit value 0400088. By adding the most significant 4 bits from the PC, we get the target address as 00400088, which is the address of the sum procedure. The same encoding is used to call sum in the avg procedure.

The jal instruction in the sum procedure

jal avg

188

Guide to RISC Processors

is encoded as 0x0c10002c, which consists of 000011 as the opcode and 0x010002c as the offset value as shown below:

Opcode

Offset

0000 11 00 0001 0000 0000 0000 0010 1100

Following the target computation process described before, we get 04000b0 by multiplying the 26-bit offset 10002c by 4. Adding the 4 most significant PC bits, we get the target address of avg as 004000b0.

Returning from a Procedure

To return from a procedure, we use

jr $ra

which reads the return address from the $ra register and transfers control to this address. In the MIPS32 architecture, the instruction following the jr instruction, which is in the branch delay slot, is executed before transferring control. However, see the following SPIM note.

SPIM note

Because the SPIM simulator does not simulate the delayed branch,

the control is transferred to the address in the $ra register.

 

 

 

Note that this instruction is a special case of the general jr instruction. In this instruction, you can specify a register that contains the target address of the jump and has the following format.

jr rs

This instruction is encoded as follows.

Opcode

Offset

0000 00

rs (5 bits)

00 0000 0000

hint (5 bits)

00 1000

 

 

 

 

 

In release 1 of the MIPS architecture, only 0 is defined as the valid hint value. This is the value SPIM uses in encoding the jr instruction. For the rs we can substitute the number of the source register. To return from a procedure, we use $ra, which is r31. Thus,

Chapter 11 Procedures and the Stack

189

substituting 31 for the rs field, we get the encoding 0x03e00008 for the jr

$ra

instruction.

 

Parameter Passing

Parameter passing in assembly language is different and more complicated than that used in high-level languages. In assembly language, the calling procedure first places all the parameters needed by the called procedure in a mutually accessible storage area (usually registers or memory). Only then can the procedure be invoked.

There are two common methods depending on the type of storage area used to pass parameters: the register method or stack method. As their names imply, the register method uses general registers to pass parameters, and the stack is used in the other method. We look at the register method in this section. Stack-based parameter passing is discussed later.

Recall from our discussion in Chapter 4 that registers $v0 and $v1 are used to return results from a procedure. Registers $a0 to $a3 are used to pass the first four parameters to procedures. The remaining parameters are passed via the stack.

We can divide procedures into two major types: leaf procedures and nonleaf procedures. Leaf procedures do not call other procedures whereas nonleaf procedures do. Simple leaf procedures do not have to use the stack if its local variables can fit the callersave registers $t0 to $t9. If this is not the case, a leaf procedure will have to use the stack. Nonleaf procedures must use the stack, at least to store the return address. We say more about these procedures later on.

Our First Program

This is a simple program to compute the sum of three integers (see Program 11.1). Our main goal is to explain the basics of the procedures in the MIPS assembly language. The main program requests three integers and passes them to the find_sum procedure. The procedure returns the sum. Registers are used for parameter passing as well as to return the result. Registers $a0, $a1, and $a2 are used to pass the three integers. The procedure returns the sum in $v0.

Program 11.1 Our first procedure example

1: # Find the sum of three numbers SUM.ASM

2:#

3:# Objective: Finds the sum of three integers.

4:

#

To demonstrate register-based

5:

#

parameter passing.

6:# Input: Requests three numbers from the user.

7:# Output: Outputs the sum.

190

Guide to RISC Processors

8:#

9:# $a0, $a1, $a2 - three numbers are passed via

10:

#

these registers

11:

#

$v0 - returns sum

12:#

13:################### Data segment ###################

14:.data

15:prompt:

16:

.asciiz

"Please enter three numbers: \n"

17:sum_msg:

18:

.asciiz

"The sum is: "

19:newline:

20: .asciiz "\n" 21:

22:################### Code segment ###################

23:.text

24:.globl main

25:main:

26:

la

$a0,prompt

# prompt user for input

27:li $v0,4

28:syscall

30:

li

$v0,5

# read 1st number into $a0

31:syscall

32:move $a0,$v0

34:

li

$v0,5

# read 2nd number into $a1

35:syscall

36:move $a1,$v0

38:

li

$v0,5

# read 3rd number into $a2

39:syscall

40:move $a2,$v0

42:jal find_sum

43:move $t0,$v0

45:

la

$a0,sum_msg

# write sum message

46:li $v0,4

47:syscall

49:

move $a0,$t0

# output sum

50:li $v0,1

51:syscall

53:

la

$a0,newline

# write newline

54:

li

$v0,4

 

Chapter 11

Procedures and the Stack

191

55:

syscall

 

56:

 

 

 

57:

li

$v0,10

# exit

58: syscall 59:

60:#------------------------------------------------

61:# FIND_SUM receives three integers in $a0, $a1,

62:# and $a2 and returns their sum in $v0

63:#------------------------------------------------

64:find_sum:

65:move $v0,$a0

66:addu $v0,$v0,$a1

67:addu $v0,$v0,$a2

68: jr $ra

To invoke the procedure, we use jal as shown on line 42. The body of the procedure is simple and straightforward to understand. When the procedure is done, a jr instruction returns control back to the main program (see line 68). Because we use addu, there will not be any overflow exception. If you want the overflow exception, use add instead of addu on lines 66 and 67.

Pros and Cons of the Register Method

The register method has its advantages and disadvantages. These are summarized here.

Advantages

1.The register method is convenient and easier for passing a small number of parameters. For example, MIPS conventionally uses $a0 to a3 to pass the first four parameters.

2.This method is also faster because all the parameters are available in registers, as opposed to in memory.

Disadvantages

1.The main disadvantage is that the register-based method is not useful as a general mechanism for parameter passing. For example, only a few parameters can be passed by using registers, as there are a limited number of them available. Later on we look at another example that passes a variable number of parameters. This example requires the use of the stack. Chapter 16, which discusses recursive procedures, also demonstrates the need for the stack in procedures.

2.Another problem is that the registers are often used by the calling procedure for some other purpose. Thus, it is necessary to temporarily save the contents of these registers on the stack to free them for use in parameter passing before calling a

192

 

 

 

 

 

 

 

 

 

 

Guide to RISC Processors

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1003

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1002

 

 

1002

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1001

 

 

1001

 

 

1001

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1000

 

 

1000

 

 

1000

 

 

1000

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Empty

After

 

 

After

 

 

After

 

 

After

 

stack

inserting

 

 

inserting

 

 

inserting

 

 

inserting

 

 

 

 

 

1000

1001

1002

1003

 

Figure 11.2 An example showing stack growth: numbers 1000 through 1003 are inserted in ascending order. The arrow points to the top-of-stack.

procedure, and restore them after returning from the called procedure. Because we use the stack to save these registers, it is difficult to realize the second advantage listed above, as the stack operations involve memory access.

For these reasons, the stack is used with procedures. Next we look at these details.

Stack Implementation in MIPS

What Is a Stack

Conceptually, a stack is a last-in-first-out (LIFO) data structure. The operation of a stack is analogous to the stack of trays you find in cafeterias. The first tray removed from the stack would be the last tray that had been placed on the stack. There are two operations associated with a stack: insertion and deletion. If we view the stack as a linear array of elements, stack insertion and deletion operations are restricted to one end of the array. Thus, the only element that is directly accessible is the element at the top-of-stack (TOS). In the stack terminology, insert and delete operations are referred to as push and pop operations, respectively.

There is another related data structure, the queue. A queue can be considered as a linear array with insertions done at one end of the array and deletions at the other end. Thus, a queue is a First-In-First-Out (FIFO) data structure.

As an example of a stack, let us assume that we are inserting numbers 1000 through 1003 into a stack in ascending order. The state of the stack can be visualized as shown in Figure 11.2. The arrow points to the top-of-stack. When the numbers are deleted from the stack, the numbers will come out in the reverse order of insertion. That is, 1003 is removed first, then 1002, and so on. After the deletion of the last number, the stack is said to be in the empty state (see Figure 11.3).

In contrast, a queue maintains the order. Suppose that the numbers 1000 through 1003 are inserted into a queue as in the stack example. When removing the numbers from the

Chapter 11 Procedures and the Stack

 

 

 

193

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1003

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1002

 

 

1002

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1001

 

 

1001

 

 

1001

 

 

 

 

 

Empty

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1000

 

 

1000

 

 

1000

 

 

1000

 

 

stack

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Initial

 

 

 

After

 

 

After

 

 

After

 

 

After

 

stack

 

 

 

removing

 

 

removing

 

 

removing

 

 

removing

 

 

1003

1002

1001

1000

 

Figure 11.3 Deletion of data items from the stack: the arrow points to the top-of-stack.

queue, the first number to enter the queue would be the one to come out first. Thus, the numbers deleted from the queue would maintain their insertion order.

Stack Implementation

MIPS does not provide any special support to implement the stack. The memory space reserved in the stack segment is used to implement the stack. The MIPS memory layout is shown in Figure 4.3, which is reproduced here for convenience as Figure 11.4. As shown in this figure, the memory from 0x10000000 to 0x7FFFFFFF is used for the data and stack segments.

The stack segment begins at the top end of this memory section (i.e., at address 0x7FFFFFFF) and grows downward. On the other hand, the dynamic data area grows upward. This is an efficient way of sharing the unused memory between the stack and data segments. As a result, we should remember that as we push more data onto the stack, the memory address decreases.

The stack is a LIFO data structure, therefore we just need to maintain a pointer to the top of the stack. In some architectures, a special register is provided to point to the top of the stack. For example, in the Intel architecture the esp register serves this purpose. In the MIPS architecture, however, there is no special register. We can use any general register for this purpose. By convention, the register r29 is used to point to the top of the stack. This register is referred to as the stack pointer register ($sp). Note that TOS points to the last item pushed onto the stack.

Stack Operations

The MIPS architecture does not explicitly support stack operations. In contrast, the Intel architecture provides instructions such as push and pop to facilitate the stack operations. In MIPS, we have to manipulate the stack pointer register to implement the stack.

194

Guide to RISC Processors

Memory addresses (in hex)

7FFFFFFF

Stack segment

Dynamic area

Data segment

Static area

10000000

Text segment

4000000

Reserved

0

Figure 11.4 Typical memory layout used by operating systems.

PUSH operation As discussed before, we have to decrement $sp to make room for the value being pushed onto the stack. For example, if we want to push the contents of $a0, we have to reserve four bytes of stack space and use the sw instruction to push the value as shown below:

sub

$sp,$sp,4

#

reserve 4 bytes of stack

sw

$a0,0($sp)

#

save the register

POP operation The operation can be implemented by using the load and add instructions. For example, to restore the value of $a0 from the stack, we use the lw instruction to copy the value and increment $sp by 4 as shown below:

lw

$a0,0($sp)

#

restore

the two registers

addu

$sp,$sp,4

#

clear 4

bytes of stack

Chapter 11 Procedures and the Stack

195

 

 

 

 

Increasing

 

 

 

 

memory

 

 

 

 

addresses

 

156

156

 

156

sp

1234

1234

 

1234

 

 

5678

sp

5678

 

sp

9012

 

9012

 

.

.

 

.

 

.

.

 

.

 

.

.

 

.

 

(a)

(b)

 

(c)

Figure 11.5 Stack implementation in MIPS: (a) initial stack state (sp points to the top-of- stack); (b) stack state after pushing 5678 and 9012; (c) stack state after removing 9012.

A Stack Example

In this example, let us consider 32-bit data even though the stack can be used for other data types. The initial state of the stack is shown in Figure 11.5a. When we push the contents of $a0 (5678) and $a1 (9012) onto this stack, the $sp is decremented by 8 to reserve eight bytes of stack space. Then the values 5678 and 9012 are stored in the stack using the code shown below:

sub

$sp,$sp,8

#

reserve 8 bytes of stack

sw

$a1,0($sp)

#

save registers

sw

$a0,4($sp)

 

 

The resulting stack state is shown in Figure 11.5b. Suppose we want to pop the stack into $t0. We can do this by the following code fragment.

lw $t0,0($sp) add $sp,$sp,4

The resulting stack state is shown in Figure 11.5c.

Uses of the Stack

The stack is used for three main purposes: as a scratchpad to temporarily store data, for transfer of program control, and for passing parameters during a procedure call.

Соседние файлы в папке MIPS_primery_zadach