# Lab2: RISC-V `RV32I[MA]` emulator with ELF support ###### tags: `RISC-V` * choose [Find Largest Element](https://hackmd.io/4-oWQOprRnCLu3ZeJy31kA?both) assembly program from [許龍君](https://github.com/jayhua267/Computer_Architecture-HW1) ```cpp= .data array: .word 9, 28, 63, 88, 52, 9, 75, 6, 26,7 range: .word 10 # range of the array str1: .string "The largest number in array of " str2: .string " is " .text #s1 = Base address of current array #s2 = i #s3 = Range to compare (10) #t0 = Flag #t1 = Current Address main: la s1, array # s1 = base address of array add s2, x0, x0 # i = 0 add t0, x0, x0 # define Flag lw s3, range # size = 10 jal ra, forloop # Jump-and-link to the 'forloop' label # Exit program li a7, 10 ecall forloop: addi s2, s2, 1 #i = i+1 lw t1,0(s1) #t1 = next value of the array addi s1, s1, 4 #update new position of the next address #if-else bge t0, t1, then #if Flag >= A[i] jump to 'then' add t0, x0, t1 #else Flag = A[i] beq s2, s3, printResult #if i = 10 => stop j forloop #back to for loop then: beq s2, s3, printResult #if i = 10 => stop j forloop #else continue run for loop printResult: la a0, str1 li a7, 4 #print string ecall mv a0, s3 li a7, 1 #print integer ecall la a0, str2 li a7, 4 ecall mv a0, t0 li a7, 1 ecall ret ``` * **Find largest element** C program by 許龍君 ```cpp= #include <iostream> using namespace std; int main() { int i, flag=0, size = 10; int arr[size] = {9,28,63,88,52,9,75,6,26,7}; // Loop to store largest number to arr[0] for(i = 0;i < size; i++) { // Change < to > if you want to find the smallest element if(flag < arr[i]) flag = arr[i] ; } cout << "The largest number in array of " << size << " is "<< flag; return 0; } ``` ## Rewrite assembly to C * **Find largest element** by myself ```cpp= #include<stdio.h> int _start() { int i; static const int arr[10] = {9, 28, 53, 88, 52, 9, 75, 6, 26, 7}; int maxNumber = arr[0]; for(i = 1;i < 10; i++) { if(maxNumber < arr[i]) maxNumber = arr[i] ; } volatile char *tx1 = (volatile char *)0x40002000; const char *result = "The largest element is "; while(*result) { *tx1 = *result; result++; } *tx1 = maxNumber; return 0; } ``` objdump a assembly program based on C as above ``` riscv-none-embed-objdump -d test1 ``` **compile in O3(optimize speed)** ```cpp= Disassembly of section .text: 00010054 <_start>: 10054: 000107b7 lui a5,0x10 10058: 08478793 addi a5,a5,132 # 10084 <_start+0x30> 1005c: 05400713 li a4,84 10060: 400026b7 lui a3,0x40002 10064: 00e68023 sb a4,0(a3) # 40002000 <__global_pointer$+0x3fff0764> 10068: 00178793 addi a5,a5,1 1006c: 0007c703 lbu a4,0(a5) 10070: fe071ae3 bnez a4,10064 <_start+0x10> 10074: 05800793 li a5,88 10078: 00f68023 sb a5,0(a3) 1007c: 00000513 li a0,0 10080: 00008067 ret ``` its ***make check*** result ``` ./emu-rv32i test1 The largest element is X >>> Execution time: 520717 ns >>> Instruction count: 101 (IPS=193963) >>> Jumps: 23 (22.77%) - 0 forwards, 23 backwards >>> Branching T=22 (95.65%) F=1 (4.35%) ``` **compile in Os(optimize size)** ```cpp= Disassembly of section .text: 00010054 <_start>: 10054: 000107b7 lui a5,0x10 10058: 08878793 addi a5,a5,136 # 10088 <_start+0x34> 1005c: 400026b7 lui a3,0x40002 10060: 0007c703 lbu a4,0(a5) 10064: 00071c63 bnez a4,1007c <_start+0x28> 10068: 400027b7 lui a5,0x40002 1006c: 05800713 li a4,88 10070: 00e78023 sb a4,0(a5) # 40002000 <__global_pointer$+0x3fff0760> 10074: 00000513 li a0,0 10078: 00008067 ret 1007c: 00e68023 sb a4,0(a3) # 40002000 <__global_pointer$+0x3fff0760> 10080: 00178793 addi a5,a5,1 10084: fddff06f j 10060 <_start+0xc> ``` its ***make check*** result ``` ./emu-rv32i test1 The largest element is X >>> Execution time: 358229 ns >>> Instruction count: 126 (IPS=351730) >>> Jumps: 47 (37.30%) - 23 forwards, 24 backwards >>> Branching T=23 (95.83%) F=1 (4.17%) ``` ### Compare between O3 and Os Less instruction count in O3, Jump is also less used. I don't really understand much about the whole code process, but I think it can already find out the answer in the compile process. and ELF file ```shell $ riscv-none-embed-readelf -h test1 ``` Output: ```cpp= ELF Header: Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 Class: ELF32 Data: 2's complement, little endian Version: 1 (current) OS/ABI: UNIX - System V ABI Version: 0 Type: EXEC (Executable file) Machine: RISC-V Version: 0x1 Entry point address: 0x10054 Start of program headers: 52 (bytes into file) Start of section headers: 560 (bytes into file) Flags: 0x0 Size of this header: 52 (bytes) Size of program headers: 32 (bytes) Number of program headers: 1 Size of section headers: 40 (bytes) Number of section headers: 7 Section header string table index: 6 ``` size ```shell $ riscv-none-embed-size test1 ``` Output: ``` text data bss dec hex filename 72 0 0 72 48 test1 ```