# Asssigment3: SoftCPU
## Setting up the Environment
### Follow the github, install RISC-V toolchains.
1. get this `xpack-riscv-none-embed-gcc-10.2.0-1.2-linux-x64.tar.gz` and do `tar zxvf xpack-riscv-none-embed-gcc-10.2.0-1.2-linux-x64.tar.gz`.
2. `cp -af xpack-riscv-none-embed-gcc-10.2.0-1.2 $HOME/riscv-none-embed-gcc`
3. cd $HOME/riscv-none-embed-gcc ,do `export CROSS_COMPILE=riscv-none-embed-`
4. `sudo apt install build-essential ccache`
5. cd $HOME
```clike=
sudo apt install autoconf automake autotools-dev curl gawk git \
build-essential bison flex texinfo gperf libtool patchutils bc git \
libmpc-dev libmpfr-dev libgmp-dev gawk zlib1g-dev libexpat1-dev
git clone --recursive https://github.com/riscv/riscv-gnu-toolchain
cd riscv-gnu-toolchain
mkdir -p build && cd build
../configure --prefix=/opt/riscv --enable-multilib
make -j$(nproc)
```
6.
```clike=
cd ~/
git clone https://github.com/sysprog21/srv32
```
7.
```clike=
$ cd $HOME/riscv-none-embed-gcc
$ echo "export PATH=`pwd`/bin:$PATH" > setenv
```
8.
```clike=
$ cd $HOME
$ source riscv-none-embed-gcc/setenv
```
9.
```clike=
cd ~/srv32/tools/
make
```
10.
```clike=
cd ~/srv32/sim/
make
```
11.
```clike=
cd ../tests/
make tests-sw
```
Then, output successed!!

## Requirement 1
First, I tried the example code in srv32(hello.c).
```c=
$ cd ..
$ make hello
```
Then, I got the print output.

Second, I tried to execute my assignment 1.
There is my C code of my [assignment 1](https://hackmd.io/@Pin-Cheng/r1U3mW-IF):
```clike=
# include <stdio.h>
# include <stdlib.h>
int isPowerOfFour(int n){
if (n==0)
return 0;
if (n==1 || n==4)
return 1;
if (n%4==0)
return isPowerOfFour(n/4);
else
return 0;
}
int main(void){
int a=256;
int ans=isPowerOfFour(a);
if (ans==1){
printf("%d is power of four\n",a);
}
else if (ans==0){
printf("%d is not power of four\n",a);
}
return 0;
}
```
I overwrite my code in sample hello.c -- `srv32/sw/hello/hello.c`.
Except `.c` , I also need the `Makefile`.
There is my `Makefile`, and I put it as `srv32/sw/hello/Makefile`.
```clike=
include ../common/Makefile.common
EXE = .elf
SRC = hello.c
CFLAGS += -L../common
LDFLAGS += -T ../common/default.ld
TARGET = hello
OUTPUT = $(TARGET)$(EXE)
.PHONY: all clean
all: $(TARGET)
$(TARGET): $(SRC)
$(CC) $(CFLAGS) -o $(OUTPUT) $(SRC) $(LDFLAGS)
$(OBJCOPY) -j .text -O binary $(OUTPUT) imem.bin
$(OBJCOPY) -j .data -O binary $(OUTPUT) dmem.bin
$(OBJCOPY) -O binary $(OUTPUT) memory.bin
$(OBJDUMP) -d $(OUTPUT) > $(TARGET).dis
$(READELF) -a $(OUTPUT) > $(TARGET).symbol
clean:
$(RM) *.o $(OUTPUT) $(TARGET).dis $(TARGET).symbol [id]mem.bin memory.bin
```
Finally, I can get my code started.

As you can see, Ouput answer `256 is power of four` is correct.
## Requirement 2
### Download GTKWave
```
$ sudo apt-get update
$ sudo apt-get install gtkwave
```
And gtkwave is in your ubuntu now.
click the gtkwave.exe

file->open `wave.fst`(../srv32/sim/).

Next, pull some signals in.

In this case, I found that the branch hazard penalty is two clock cycles.

## Requirement 3
After the simulation of the RISCV-gcc toolchain generated assembly file, I found that there are some places of my origin code to get better.
I found the assembly file generated by RISCV-gcc toolchain is in `/srv32/sw/hello/hello.dis`. So I look at it.
### Fewer instructions
* As for some instruction, actually I don't need to do those everytime when the function called.
Details
In my origin code:
This is a loop for my function, everytime when the function is called recursively, it will go through those instructions.
The assignment in `line 5` and `line 6`, it will be assigned everytime as 1 and 4, this is not necessary.
```clike=
isPowerOfFour:
addi sp, sp, -4
sw ra, 0(sp)
beq a0, zero , false
addi t3, zero, 1
addi t6, zero, 4
beq a0, t3 , true
beq a0, t6 , true
loop:
andi t4 , a0 , 3
bne t4,zero,false
srli a0,a0,2
jal ra, isPowerOfFour
add a1,t5,a1
j res2
```
In RISCV-gcc toolchain assembly file:
It just need to assign one time(`line 54`, `line 58`) , out of the function loop code that `line 64` to `line 84` is function loop.
```clike=
54: 00100713 li a4,1
58: 00400693 li a3,4
5c: 00078a63 beqz a5,70 <isPowerOfFour+0x34>
60: 0340006f j 94 <isPowerOfFour+0x58>
64: 02e50463 beq a0,a4,8c <isPowerOfFour+0x50>
68: 02d50263 beq a0,a3,8c <isPowerOfFour+0x50>
6c: 02079463 bnez a5,94 <isPowerOfFour+0x58>
70: 41f55793 srai a5,a0,0x1f
74: 0037f793 andi a5,a5,3
78: 00a78533 add a0,a5,a0
7c: 40255513 srai a0,a0,0x2
80: 00357793 andi a5,a0,3
84: fe0510e3 bnez a0,64 <isPowerOfFour+0x28>
```
### Eliminate unnecessary stalls
* Some instructions with RAW data hazard must encounter stall to let the pipeline can get the data correctly.
Details
In my origin code:
In every loop, I have to do this which leads to a stall.
```clike=
andi t4 , a0 , 3
bne t4,zero,false
```
In RISCV-gcc toolchain assembly file:
But actually, we can deal with this problem. It executes the value of `andi t4 , a0 , 3` in the end of last loop, so it doesn't have to do this in the current loop.
As you can see,
the `andi` is executed at the end of the loop(line 80).
And the `bne` is executed at the top of the loop(line 6c).
So they did't encounter hazard.
```clike=
64: 02e50463 beq a0,a4,8c <isPowerOfFour+0x50>
68: 02d50263 beq a0,a3,8c <isPowerOfFour+0x50>
6c: 02079463 bnez a5,94 <isPowerOfFour+0x58>
70: 41f55793 srai a5,a0,0x1f
74: 0037f793 andi a5,a5,3
78: 00a78533 add a0,a5,a0
7c: 40255513 srai a0,a0,0x2
80: 00357793 andi a5,a0,3
84: fe0510e3 bnez a0,64 <isPowerOfFour+0x28>
```
## Requirement 4
The progresses of how srv32 works are already recorded in the former of my note.
In order to achieve this homework, I have learned many things, including srv32 pipeline and its waveform.
###### tags: `jserv Computer Architecture 2021`