2:Compile the same code using the RISC-V compiler to generate its assembly code. Then, evaluate the RISC-V assembly code for the sample C program by using two different compilation options.
- Install virtualbox
- Launch the Virual box
- Create a new Virtual Machine
- Select Linux as the operating system and under version choose Ubuntu 18.04
- Attach th VDI files to the machine
- Start the machine
- open a terminal
- Install LeafPad,a simple text editor by running the following command
sudo-get install leafpad
- To navigate to the home directory,enter the following command
cd
- To open a blank file for typing C program,enter the following command
leadfpad sum1ton.c
- After writing the program,save it and return to the terminal and enter the following command
gcc sum1ton.c
./a.out
- verify the result using a calculator
- after verifying it go back to the editor and check the result for different values of n
- recompile it and verify the output
- To display the content of the C code in the terminal,use the following command
cat sum1ton.c
- To run the C code using RISC-V compiler and to generate the object file,enter the following command
riscv64-unknown-elf-gcc -O1 -mabi=lp64 -march=rv64i -o sum1ton.o sum1ton.c
ls -ltr sum1ton.o
- Create a new tab and enter the following command to generate the assembly code
riscv64 -unknown-elf-onjdump-d sum1ton.o
- the system will generate huge assembly code
- to get the main parts of the program, enter the following command
riscv64 -unknown-elf-objdump -d sum1ton.o | less
- to focus on the main code , enter the following command and press"n"
/main
- count the number of instructions and verify using programmable calculator
- return to the terminal and enter the following command
riscv64-unknown-elf-gcc -Ofast -mabi=lp64 -march=rv64i -o sum1ton.o sum1ton.c
- To compile and debug a C code in RISC-V and verify its output.
- Compile the following C code in the terminal
#include<stdio.h>
int main(){
int i,sum=0,n=100;
for(i=1;i<=n;++i){
sum+=i;
}
printf("sum of numbers from 1 to %d is %d\n",n,sum);
return 0;
}
- Compile the code using the RISC-V compiler with the following command.
riscv64-unknown-elf-gcc -Ofast -mabi=lp64 -march=rv64i -o sum1ton.c sum1ton.o
- Execute on spike with the following command
- This should yield the same results as before, verifying that the instructions are functioning correctly.
spike pk sum1ton.o
- First, open the objdump of the file using the following command.
riscv64-unknown-elf-objdump -d -sum1ton.o
riscv64-unknown-elf-objdump -d -sum1ton.o | less
- To debug the assembly code, using Spike
spike -d pk sum1ton.o
- To start debugging from a specific address, check the initial memory location of the first instruction.
-As indicated in the highlighted code above, this is the initial memory location of the first instruction
- The command
bash "until pc 0 bc100"
is used to run the program counter until it reaches the first instruction
-To find the content of a2, use the following command
reg 0 a2
- It will start from the zero bit and press enter to run the next instruction
- run the following command to get the content o of a2
reg 0 a2
- Press enter to load the next instruction
-enter the following command and press enter to load the next instruction
reg 0 a0
-To retrieve the content of the stack pointer, enter the following command:
reg 0 sp
- The "addi" instruction updates the stack pointer by adding an immediate value to it.
- the command "addi sp,sp,16 decreases the stack pointer by 16 in decimal or 10 in hexadecimal
-quit and enter the command
spike -d pk sum1ton.o
until pc 0 100b8
reg 0 b8
-enter the following command to look into stack pointer
reg 0 sp
-Using a calculator to confirm
0xffffffb50 - 0x10 = 0xffffffb40
- the result confirms that the command successfully decrements the stack pointer register by 0*10.
1) List various RISC-V instruction type (R, I, S, B, U, J) after going through RISC-V software documentation
- RISC-V (Reduced Instruction Set Computer - V) instructions are the set of commands used in RISC-V processors to perform various operations, including arithmetic, data movement, control flow, and more. RISC-V instructions are designed to be simple, modular, and extensible, making it easy to customize for specific applications or add new features.
- RISC-V instructions are divided into different categories based on functionality.
- Purpose: Used for arithmetic and logical operations between two registers.
- Format: opcode | rd | funct3 | rs1 | rs2 | funct7
- opcode: Operation type (7 bits)
- rd: Destination register (5 bits)
- funct3: Specifies the function (3 bits)
- rs1: First source register (5 bits)
- rs2: Second source register (5 bits)
- funct7: Additional function code (7 bits)
- Purpose: Used for operations involving an immediate value (constant), such as load and arithmetic with constants.
- Format: opcode | rd | funct3 | rs1 | immediate
- opcode: Operation type (7 bits)
- rd: Destination register (5 bits)
- funct3: Specifies the operation (3 bits)
- rs1: Source register (5 bits)
- immediate: Immediate value (12 bits, sign-extended)
- Purpose: Used for store operations, writing data from a register to memory.
- Format: opcode | immediate[4:0] | funct3 | rs1 | rs2 | immediate[11:5]
- opcode: Operation type (7 bits)
- funct3: Specifies the store type (3 bits)
- rs1: Base address register (5 bits)
- rs2: Source register to store (5 bits)
- immediate: Split into two parts to form a 12-bit address offset (5+7 bits)
- Purpose: Used for conditional branching, changing control flow based on comparisons.
- Format: opcode | immediate[11] | immediate[4:1] | funct3 | rs1 | rs2 | immediate[10:5]
- opcode: Operation type (7 bits)
- funct3: Specifies the branch condition (3 bits)
- rs1, rs2: Registers to compare (5 bits each)
- immediate: Split into multiple parts, sign-extended to 13 bits to specify the branch offset
- Purpose: Used to handle large immediate values, mainly for setting the upper 20 bits of a register.
- Format: opcode | rd | immediate[31:12]
- opcode: Operation type (7 bits)
- rd: Destination register (5 bits)
- immediate: Immediate value, upper 20 bits (20 bits)
- Purpose: Used for unconditional jumps, typically for function calls.
- Format: opcode | rd | immediate[20 | 10:1 | 11 | 19:12]
- opcode: Operation type (7 bits) rd: Register to store the return address (5 bits) immediate: 20-bit offset, sign-extended and reordered to specify the jump target address.
1.addi sp,sp,16
2.auipc a5, 0xFFFF0
3.sub a2, a2, a0
4.jal ra, 0x102EC
5.lw a0, 0(sp)
6.lbu a5, 1944(gp)
7.bnez a5, 0x1018C
9.sd ra, 8(sp)
10.xori a5, a5, -2000
11.slli a5, a3, 0x30
12.bqez a5, 101f4
13.bltu a3, a5, 138ac
14.ld a3, 16(a2)
15.add s1, s0, s1
SL no | Instruction | Instruction Type | 32-bit Instruction Code |
---|---|---|---|
1 | addi sp, sp, 16 |
I-type | 0x00108093 |
2 | auipc a5, 0xFFFF0 |
U-type | 0xFFFF0801 |
3 | sub a2, a2, a0 |
R-type | 0x40A30333 |
4 | jal ra, 0x102EC |
J-type | 0x102EC06F |
5 | lw a0, 0(sp) |
I-type | 0x00010083 |
6 | lbu a5, 1944(gp) |
I-type | 0x79858103 |
7 | bnez a5, 0x1018C |
B-type | 0xF8E58063 |
8 | sd ra, 8(sp) |
S-type | 0x00E12023 |
9 | xori a5, a5, -2000 |
I-type | 0xFFFF8033 |
10 | slli a5, a3, 0x30 |
R-type | 0x03035013 |
11 | bqez a5, 101F4 |
B-type | 0x00128063 |
12 | bltu a3, a5, 138AC |
B-type | 0x02F38063 |
13 | ld a3, 16(a2) |
I-type | 0x01030303 |
14 | add s1, s0, s1 |
R-type | 0x00308233 |