0% found this document useful (0 votes)
2 views

Lab5

The document outlines Lab #5 for a Computer Architecture course, focusing on recursive function calls and assembler directives in RISC-V assembly language. It explains the compilation of recursive functions, specifically the factorial function, and details the use of assembler directives for managing global variables and memory segments. Additionally, it includes laboratory tasks for implementing recursive matrix multiplication using RISC-V assembly code.

Uploaded by

omarashraf13456
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
2 views

Lab5

The document outlines Lab #5 for a Computer Architecture course, focusing on recursive function calls and assembler directives in RISC-V assembly language. It explains the compilation of recursive functions, specifically the factorial function, and details the use of assembler directives for managing global variables and memory segments. Additionally, it includes laboratory tasks for implementing recursive matrix multiplication using RISC-V assembly code.

Uploaded by

omarashraf13456
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 12

Department of Computer Science

Institute of Business Administration, Karachi

Lab #5: Recursive Function Calls & Assembler


Directives in RISC-V Assembly Codes

Computer Architecture & Assembly Language


February 19, 2024

Course Instructor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Salman Zaffar


Lab Instructor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Mehwish Zafar
Week Performed . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . : Week 1
Room . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . MTL4

1 Introduction
There are two purposes of this lab. These are
1. to introduce the compilation of recursive function calling (of C language) into RISC-V
assembly.
2. to understand the assembler directives in RISC-V assembly language

2 Recursive Functions without Assembler Directives


A recursive function is a nonleaf function that calls itself. Recursive functions behave as both
caller and callee and must save both preserved and nonpreserved registers. For example,
the factorial function can be written as a recursive function. Recall that factorial(n) = n ×
(n − 1) × (n − 2) × . . . × 2 × 1. The factorial function can be written recursively as factorial(n)
= n × factorial(n – 1), as shown in Code Example 6.28.

1
Figure 1: Recursive Function Call

The factorial of 1 is simply 1. To conveniently refer to program addresses, we show the


program starting at address 0x8500. According to the callee save rule, factorial is a nonleaf
function and must save ra. According to the caller save rule, factorial will need n after
calling itself, so it must save a0. Hence, it pushes both registers onto the stack at the start.
It then checks whether n ≤ 1. If so, it puts the return value of 1 in a0, restores the stack
pointer, and returns to the caller. It does not have to restore ra in this case, because it was
never modified. If n > 1, the function recursively calls factorial(n-1). It then restores the
value of n and the return address register (ra) from the stack, performs the multiplication,
and returns this result. Notice that the function cleverly restores n into t1 so as not to
overwrite the returned value. The multiply instruction (mul a0, t1, a0) multiplies n (t1)
and the returned value (a0) and puts the result in a0, the return register. For clarity, we
save registers at the start of a function call. An optimizing compiler might observe that
there is no need to save a0 and ra when n ≤ 1 and, thus, save registers on the stack only in
the else portion of the function.
Figure 2 shows the stack when executing factorial(3). For illustration, we show sp
initially pointing to 0xFF0 (the upper address bits are 0), as shown in Figure 2(a). The
function creates a two-word stack frame to hold n (a0) and ra. On the first invocation,
factorial saves a0 (holding n = 3) at 0xFEC and ra at 0xFE8, as shown in Figure 2(b). The
function then changes n to 2 and recursively calls factorial(2), making ra hold 0x8528. On
the second invocation, it saves a0 (holding n = 2) at 0xFE4 and ra at 0xFE0. This time,
we know that ra contains 0x8528. The function then changes n to 1 and recursively calls
factorial(1). On the third invocation, it saves a0 (holding n = 1) at 0xFDC and ra at 0xFD8.
This time, ra again contains 0x8528. The third invocation of factorial returns the value 1 in
a0 and deallocates the stack frame before returning to the second invocation. The second
invocation restores n (into t1) to 2, restores ra to 0x8528 (it happened to already have this
value), deallocates the stack frame, and returns a0 = 2 × 1 = 2 to the first invocation.
The first invocation restores n (into t1) to 3, restores ra, the return address of the caller,
deallocates the stack frame, and returns a0 = 3 × 2 = 6.

2
Figure 2: Stack: (a) before, (b) during, and (c) after factorial function call with n = 3

Figure 2(c) shows the stack as the recursively called functions return. When factorial
returns to the caller, the stack pointer is in its original position (0xFF0), none of the contents
of the stack above the pointer have changed, and all of the preserved registers hold their
original values. a0 holds the return value, 6.

3
Figure 3: Complete run-through factorial code in Code Example 6.28 for n=4

4
3 Recursive Functions with Assembler Directives
Assembler directives guide the assembler in allocating and initializing global variables, defin-
ing constants, and differentiating between code and data. Table 6.5 in the book lists common
RISC-V assembler directives. Let us discuss the assembler directives given in Figure 3 now

1. The program begins by making the main label global (.globl main) so that the main
function can be called from outside this file, typically by the OS or bootloader.
2. Next, the program allocates the following global variables A (a 7−element array of
32−byte values), B (an element), and str1 (a null−terminated string). A, B, and str1
are initialized, respectively, to 5, 42, −88, 2, −5033, 720, 314, 0x9, and “RISC−V”
(i.e., 52, 49, 53, 43, 2D, 56, 00. These global variables are stored in data segment of
the memory which starts from 0x00000 000.
3. .text specifies the beginning of user code which is stored in the text segment of main
memory which starts from 0x10000 000. This is actually the instruction memory.

4. There is a assembler-specific pseudo-instruction la which loads the starting address of


global variable A. The second instruction loads the actual content of memory location
A into the register a0.

5
Figure 4: Code with Assembler Directives

6
Figure 5: Asembler directives to store global variables in data segment of the main memory

4 Laboratory Tasks
Implement the 2x2 multiplication with all the elements of Matrices A, B and resultant in
the data segment of the main memory. Use Recursive Function Call to implement Matrix
multiplication.

Figure 6: 2x2 Matrix Multiplication

7
1. Fill the parts of code below for Recursive Matrix Multiplication.

. data
matrix1 : . word 1 , 2 , 1 , 2
matrix2 : . word 1 , 2 , 1 , 2
result : . word 0 , 0 , 0 , 0

. text

main :
# LOAD THE ADDRESSES OF ALL THREE MATRICES INTO REGISTERS ( USING la )
# USE s0 , s1 , & s2 registers for loading addresses of matrices .

# INITIALIZE THE STARTING & ENDING INDEX OF FOR LOOP ( using addi )

# INITIALIZE THE VALUE OF ra

for :

# Recursive Call to R e c u r s i v e _ M u l t i p l i c a t i o n using ( jal )

Recursive_Multiplcation :

# Decrement sp by -16 to make space for four words on stack

# Store the preserved registers onto to the stack

8
# Matrix Multipli cation Code

# Restore values from stack onto the registers

# Increment the sp by 16

# return

done :

9
2. Provide a screenshot of Memory Address section that depicts the values of input and
resultant matrices. Highlight it in the screenshot.

3. Write the values of the mentioned registers in HEX form:

Register Value

ra
sp
gp
s0
s1
s2

10
Figure 7: RISC-V Base ISA

11
12
Figure 8: Complete Single-Cycle RISC-V Microarchitecture

You might also like