Lab 4 - RISC-V Simulator

Lab 4 - RISC-V Simulator

In this laboratory, you will learn more about assembly language programming and learn how to use the RARS RISC-V simulator. This RISC-V instruction-set simulator will allow you to simulate the executions of individual instructions operating on the RISC-V processor. Instruction set simulators are helpful for a number of purposes including understanding the details of an instruction set, improving low-level processor performance, and understanding execution time.

Avg Hours: 5.5 (Winter 2021)

Learning Outcomes

  • Learn how to write RISC-V assembly language programs
  • Learn how to use the RARS RISC-V simulator
  • Create programs in assembly language and simulate them


In this laboratory you will be reviewing and writing a number of RISC-V assembly language programs. It will be important for you to understand assembly language programs and write functioning assembly language programs for this lab. Although the textbook provides some simple examples of RISC-V assembly language instructions and code segments, it does not provide an adequate description for writing full assembly language programs. Read and review the following Assembly Language Tutorial to learn more about assembly language programming for the RISC-V. After reading this tutorial, answer the following questions. Answers to these questions will be found in the tutorial and Chapter 2 of the textbook.

Summarize the difference between binary machine language, assembly language, and high-level source files like C.

Contrast the difference between a compiler, assembler, and linker

Determine the purpose of the stack, text segment, data segment, etc.

Determine the order of these memory segments in memory (see Figure 2.13).

Match the register with its purpose

What is a ‘pseudo instruction’?

Identify the ‘pseudo instruction’s in the instruction list

Identify the actual instruction sequence associated with the following pseudo instruction: li t1, 0


Exercise #1 - Introduction to RARS

In this exercise, you will review three different assembly language programs and will execute these programs on the RARS simulator. This exercise will help you become more familiar with RISC-V assembly language programming and become more familiar with the RARs simulator. This exercise will use the RARS Java RISC-V simulator. This Java JAR file has been included in the lab starter code at /resources/rars1_4.jar. You can execute the simulator from the /lab04/ directory by executing the following command:

java -jar ../resources/rars1_4.jar

The GUI is organized into two tabs. The first tab is the editor window for entering assembly programs. The second tab is the execute tab that simulates the assembly language programs entered in the first tab. The program must be assembled before the execute tab can be opened. The buttons at the top of the simulator allow you to run the program to completion, step through the instructions, go back a step, reset all registers and memory, and dump the machine code to your clipboard. On the right of the simulator, you can view all the contents of RISC-V registers. The GUI for RARS is shown below:

The memory contents can be viewed below. In the memory section, you can jump to memory locations for text, data, heap, and stack. One additional feature is that you can click the checkbox to the left of an instruction creating a breakpoint. With a breakpoint, when you click run and execute the program, the program will halt when it reaches the next breakpoint.

In addition to Chapter 2 from the textbook, you will need access to the online The RISC-V Instruction Set Manual to complete this lab. We will be using the 32-bit (RV32I) instructions. RISC-V instructions for the RV32I used by this simulator can be found in pages 13-29 (pdf pages 31-47) and 35-37. Pages 129-136 (pdf pages 147-154) provide a reference for RISC-V assembly language instructions.

There is a help menu within the program that provides details on how to use this simulator. The video linked below provides additional backgrond on the simulation.

Use the RARs simulator to answer the following questions. For memory location responses, provide your response as 8-digit hex values using lower case letters (i.e., ffffffff)

What is the default memory address of the start of the text segment for the simulator? (GUI: Settings: Memory Configurations)

What is the memory address of the start of the static data in the data segment for the simulator (GUI: Settings: Memory Configurations)

What is the memory address of the start of the dynamic data (heap) in the data segment for the simulator? (GUI:Settings: Memory Configurations)

What is the memory location of the stack segment for the simulator? (GUI: Settings: Memory Configurations)

Example #1

The first assembly example computes the factorial of an input value and writes the result to the output memory location. This file is located in the repository starter code at /lab04/example_1.s. The program provides a basic example of branches, loads, saves, and arithmetic.
Step through the program to understand how it works.
The program will not stop but will loop at the end.

How many extended (pseudo) instructions are there in this example? (note that using ‘lw’ with a label is a pseudo instruction)

What does the last instruction do?

What is the cycle count when the simulator gets to the first “j exit_loop”? (step through the program). Note that the cycle count can be found in the simulator under the “control and status” tab (see “cycle”).

What is the actual instruction sequence represnted by the pseudo instruction “lw a0,input”?

Example #2

The second example builds upon the first factorial exampleby adding system calls and placing the factorial function in a basic subroutine. This file is located in the repository starter code at /lab04/example_2.s. The system calls provide basic printout features and a program exit.

What printed out when the program is executed?

What is the cycle count when the program finishes?

What system calls are used in this example?

In what register does the “jal fact_func” instruction store the return address?

What is the 32-bit value located at address 0x10010008 of the data segment?

Example #3

The third example adds a complete calling convention to the factorial subroutine using the stack to help you see how the stack works. This file is located in the repository starter code at /lab04/example_3.s. This program will take more cycles to execute but it performs the same function. The stack allows you to call sub routines within your main function without messing up the data in the calling function. You will need to write a function in a later exercise that uses the stack.

What is the cycle count when the program finishes?

What is the smallest value that the stack pointer (sp) reaches during the execution of the program?

Which registers are saved on the stack at the start of the ‘fast_func’ procedure?

Exercise #2 - Factorial Example

The C code shown below is a recursive function to compute the factorial of a value. This exercise presents the assembly version of this C code and provides an example of how the stack is used in a recursive function. The assembly code for this example is found at /lab04/fact_rec.s in the starter code. Carefully review it to understand how the stack frame is used to implement recursion. Load it into the RARS simulator and execute it to see how it operates.

int fact_func(int n) {
    if (n>=1)
        return n*fact_func(n-1);
        return 1;

Answer the following questions regarding this assembly language program:

Determine the address of the “fact_func” procedure within the .text segment

What is the address where the ascii string “! = “ is stored?

What is the value of the stack pointer before the program executes?

Change the code to compute a factorial of 10. Step through the execution of this program to see the program being executed and answer the following questions:

How many instructions were executed to compute the factorial of 10?

What is the smallest value of the stack pointer during the execution when finding the factorial of 10?

Exercise #3 - Fibinocci Number

For this exercise, you will create two different RISC-V assembly language programs that output the n’th Fibonacci Number. The Fibonacci numbers are defined with recursion as follows:

  • F(0) = 0
  • F(1) = 1
  • F(n) = F(n-1) + F(n-2) (for n>=2)

For example, if the input is n=3, your program should return “2” (F(3) = 2). The first version of the Fibonacci Number will be done using an iterative method and the second version will be done using recursion.

We have provided a template for you to use to create your Fibinocci functions: /lab04/fib_template.s.
You will need to modify the function call to your Fibinocci function. You will have two different files when you are done: one for the iterative version and one for the recursive version. Copy the template into two different files - one for the iterative version (name this file fib_iterative.s) and one for the recursive version (name this file fib_recursive.s). Note that you will need to follow the Assembly language coding standards when you write your code.


Implement the first version of this function using an “iterative” approach and name your file fig_iterative.s. Sample C code for computing Fibinocci numbers iteratively is shown below:

int fib_iterative(int a) {
  if (a==0) return 0;
  if (a==1) return 1;
  int fib_2 = 0;
  int fib_1 = 1;
  int fib = 0;
  for (int i=2;i<=a;i++) {
    fib = fib_1 + fib_2;
    fib_2 = fib_1;
    fib_1 = fib;
  return fib;

Note that this code is given only as an example to help you get started. You don’t have to implement your iterative Fibonacci exactly as shown. You can modify the approach however you like so long that it provides the correct result and does not use recursion.

How many iterations of the loop will be executed for fib_iterative(5)?

How many clock cycles did it take for your code to process fib_iterative(10)?

You will need to include the iterative Fibonacci sequence code (fib_iterative.s) in your GitHub repository.


Implement the second version of this function using a “recursive” approach and name your file fig_recursive.s. C code for computing Fibinocci numbers recursively is shown below:

int fib_recursive(int a) {
  if (a==0) return 0;
  if (a==1) return 1;
  return fib_recursive(a-1) + fib_recursive(a-2);

The recursive version looks simpler than the iterative code but the recursive version will make multiple, repetitive calls for the same Fibinocci number.

Determine the number of times the function fib_recursive is called when calling the function with an input of 5 (i.e, fib_recursive(5)). Include the first call to the function in our count. You may want to write out the recursive call history to figure out this number.

How many clock cycles did it take for your code to process fib_iterative(10)?

You will need to include the recursive Fibonacci sequence code (fib_recursive.s) in your Git repository.

Pass Off

To create your submission, make sure the following files are submitted in your ‘lab04’ directory:

  • fib_iterative.s
  • fib_recursive.s

Make sure you do not add unnecessary files (including Vivado project files) to your repository. Tag your repository with the string lab4_submission and push your repository back to the origin. Test your submission by running the pass-off script found in the starter code. Review the instructions for submitting and passing off labs to make sure you have completed the lab properly.

How many hours did you work on the lab?

Provide any suggestions for improving this lab in the future.

Last Modified: 2022-05-31 12:23:24 -0500