# Lab3: Reindeer - RISCV RV32I[M] Soft CPU
###### tags: `Computer Architecture 2020`
## Modify the assembly programs used/done with HW1 or HW2 as new test case(s) for Reindeer Simulation with Verilator.
### Compile .S into .elf
First of all, we need to get ELF file. To acheive it, we can use [riscv-compliance](https://github.com/riscv/riscv-compliance). To check if it can run, you can just configure some variable in Makefile under root folder. Following is my modification:
```
export RISCV_TARGET ?= riscvOVPsim
export RISCV_DEVICE ?= rv32i
export RISCV_PREFIX ?= riscv-none-embed-
export RISCV_TARGET_FLAGS ?=
export RISCV_ASSERT ?= 0
export TARGET_SIM ?= /home/steven/Desktop/imperas-riscv-tests/riscv-ovpsim/bin/Linux64/riscvOVPsim.exe
```
Note: Procedure of seting `RISCV-PREFIX` can reference [lab2](https://hackmd.io/@sysprog/2020-arch-homework2).
Then, just type `make`:
```
...
Compare to reference files ...
Check I-FENCE.I-01 ... OK
--------------------------------
OK: 1/1 RISCV_TARGET=riscvOVPsim RISCV_DEVICE=rv32Zifencei RISCV_ISA=rv32Zifencei
make[1]: Leaving directory '/home/steven/Desktop/riscv-compliance'
```
Above is expected output.
After basic test, back to our goal - generate testing file for `Verilator` and it needs elf file. To ensure variable in makefile is right, we overwrite it again:
```
RISCV_PREFIX := riscv-none-embed-
RISCV_TARGET := riscvOVPsim
RISCV_DEVICE := rv32i
TARGETDIR := ../../riscv-target
ROOTDIR := /home/steven/Desktop/riscv-compliance
TARGET_SIM := /home/steven/Desktop/imperas-riscv-tests/riscv-ovpsim/bin/Linux64/riscvOVPsim.exe
```
Then we can observe some relative target in Makefile:
```
%.elf: $(src_dir)/%.S
$(V) echo "Compile $$(@)"
@mkdir -p $$(@D)
$(V) $(COMPILE_TARGET)
.PRECIOUS: $(work_dir_isa)/%.elf
```
We can compile .S file into elf file just using `make xxxx.elf`
Reference output:
```
echo "Compile HW3.elf"
Compile HW3.elf
riscv-none-embed-gcc -march=rv32i -mabi=ilp32 -static -mcmodel=medany -fvisibility=hidden -nostdlib -nostartfiles -
I/home/steven/Desktop/riscv-compliance/riscv-test-env/ -I/home/steven/Desktop/riscv-compliance/riscv-test-env/p/ -I../../riscv-target/riscvOVPsim/ -
T/home/steven/Desktop/riscv-compliance/riscv-test-env/p/link.ld src/HW3.S -o HW3.elf; riscv-none-embed-
objdump -D HW3.elf > HW3.elf.objdump
```
Now we can find `xxx.elf` under `/rv32i`.
Following is the example of the usage of `.fill`:
```
.fill repeat , size , value
```
As result,
```
test_1_res:
.fill 3, 4, -1
```
means will fill the data below in `.data` section:
```
ffffffff
ffffffff
ffffffff
000.....
```
Then, we can test for compiling .S file into .elf. Following is sample .S file:
```
initial1:
la x5, test_1_res
li x1, 0x01
li x2, 0x66
li x3, 0x55
sw x1, 0(x5)
sw x2, 4(x5)
sw x3, 8(x5)
```
Use `make xxx.elf` and `make xxx.log`, we can saw data writen in `.data`. Just open `xxx.signature.output`:
```
00000001 # x1
00000066 # x2
00000055 # x3
00000000
```
After easy checking, we can rewrite assembly in lab1. I choose my topic which is Leetcode problem. Source code can get on [gist](https://gist.github.com/eecheng87/7063130a1ca057a1288540c956589ce9). There is few portion need to change -
1. Get address where store answer later:
```
init:
la a1, test_1_res
main:
...
```
2. Write answer into target section:
```
# --- print ---
print:
sw t5, 0(a1)
```
3. Fill data section (input) before compiling:
```
.data
arr: .word 5, 1, 1, 1, 9, 5, 5, 9, 4, 9
len: .word 10
```
4. Initialize output section (test_1_res):
```
test_1_res:
.fill 3, 4, -1
```
Again, use `make xxx.elf` and `make xxx.log`. You can see answer writen into `signature.output`.
### Verify .S file
We need some mechanism to check if our .S file is doing the thing we expected. To make it, we can use riscv-compilance's function: `RVTEST_IO_ASSERT_GPR_EQ`. Using same code above, the only thing we need to do is appending these code:
```
RVTEST_IO_CHECK()
RVTEST_IO_ASSERT_GPR_EQ(x5, t5, 0x4)
```
`0x4` is expected value. Also there are two more things we need to do:
1. Add `xxx` in `Makefrag` and then we can use easy way to verify all .S file.
2. Add answer generated by `make xxx.elf` into `/reference` (need to change file name into xxx.ref....)
Back to root, type `make`. Bunch of test bench was testing. Following is sample output:
```
make[2]: Leaving directory '/home/steven/Desktop/riscv-compliance/riscv-test-suite/rv32i'
riscv-test-env/verify.sh
Compare to reference files ...
Check HW3 ... OK
Check I-ADD-01 ... OK
...
Check I-XORI-01 ... OK
--------------------------------
OK: 49/49 RISCV_TARGET=riscvOVPsim RISCV_DEVICE=rv32i RISCV_ISA=rv32i
```
As you can see, our test case `HW3` was added and verified!
## Check the generated VCD file and use GTKwave to view the waveform
First, clone Reindeer and change directory to `/sim/compilance` and add all generated files into it. Files contain xxx.elf, xxx.elf.odjdump ...
Then change directory into `/sim/verilator` and type `make test HW3`. Following is reference output:
```
...
1995 80000050 00051063
1996 80000050 00051063
1997 80000040 00001f17
1998 80000040 00001f17
1999 80000044 fc3f2023
=============================================================
Simulation exit ../compliance/HW3.elf
Wave trace HW3.vcd
=============================================================
====> Test PASSED, Total of 1 case(s)
```
Finally we can see `.vcd` under `/verilator`, next step is using [gtkwave](https://github.com/gtkwave/gtkwave) to view vcd file.
Ensure you have installed gtkwave and then you can use it in global.
```
gtkwave HW3.vcd
```
Following is reference output, you can choose any signal you are interested. The change of each signal is shown.

## Write down your thoughts and progress in HackMD notes (Q&A)
### What is 2 x 2 Pipeline? How can we benefit from such pipeline design?
It is special design for Reindeer, each stage of 2 x 2 Pipeline is active every other clock cycle. In this way, the Instruction Fetch and Memory Access always happen on different clock cycles, thus to avoid the structural hazard caused by the single port memory.
### What is “Hold and Load”?

After reset, the soft CPU will be put into a hold state, and it will have access to the UART TX port by default. But a valid debug frame sending from the host PC can let OCD to reconfigure the mux and switch the UART TX to OCD side, for which the memory can be accessed, and the control frames can be exchanged. A new software image can be loaded into the memory during the CPU hold state, which gives rise to the name "hold-and-load".
After the memory is loaded with the new image, the OCD can setup the start-address of the soft CPU, and send start pulse to make the soft CPU active. At that point, the OCD can switch the UART TX back to the CPU side for CPU's output.
### How Reindeer works with Verilator
### Summarize how RISC-V Compliance Tests works and why the signature should be matched.
### Can you show some signals/events inside Reindeer and describe?