owned this note
owned this note
Published
Linked with GitHub
## Lab3: Reindeer - RISCV RV32I[M] Soft CPU
###### tags: `Computer Architecture`
## Reqirement
* According to [Lab3: Reindeer - RISCV RV32I[M] Soft CPU](https://hackmd.io/@sysprog/rJw2A5DqS), we can install the soft CPU successfully.
* Read below document to install the environment
* [RISC-V Compliance Tests](https://github.com/riscv/riscv-compliance/blob/master/doc/README.adoc)
* [riscv-tests](https://github.com/riscv/riscv-tests)
* [Reindeer](https://github.com/PulseRain/Reindeer)
* After reading RISC-V Compliance Tests, I found that if we want to run compliance tests, we have to add some commands in a Makefile.include which is located at `/home/yuhong/computer_architechure/riscv-compliance/riscv-test-suite/rv32i` the code below is the command added in the Makefile
```c=
TARGETDIR:=/home/yuhong/computer_architechure/riscv-compliance/riscv-target
RISCV_TARGET:=riscvOVPsim
RISCV_DEVICE:=rv32i
```
* After adding above command, we should add some command at another Makefile which is located at `/home/yuhong/computer_architechure/riscv-compliance/riscv-target/riscvOVPsim/device/rv32i` and the code below is to be added
```c=
ROOTDIR ?= /home/yuhong/computer_architechure/riscv-compliance/
TARGET_SIM ?= /home/yuhong/computer_architechure/riscv-compliance/riscv-ovpsim/bin/Linux64/riscvOVPsim.exe
RISCV_PREFIX ?= riscv-none-embed-
RISCV_GCC ?= $(RISCV_PREFIX)gcc
RISCV_OBJDUMP ?= $(RISCV_PREFIX)objdump
RISCV_GCC_OPTS ?= -static -mcmodel=medany -fvisibility=hidden -nostdlib -nostartfiles
```
The `RISCV_PREFIX ?= riscv-none-embed-` is the GNU toolchain we used in [Lab1: R32I Simulator](https://hackmd.io/ZHsZ-7HBTvqtH8SoDHxQoQ)
* OK,now we have finished the environment setting. We can start to code.
## souce code from assignment1
### 99 multiplication table
Below is the source code from assignment produced by my freined Fred. The code is do a 9*9 multiplication table, and it print the result.
```c=
.data
mul: .string "*"
spa: .string " "
row: .string "\n"
equ: .string "="
.text
main:
addi s0, zero, 1 # i = 1
loop1: #for i loop
slti t0, s0, 10 #if(i<10)
beq t0, zero, exit #if(i>=10) go exit
addi s1, zero, 1 #else set j=1
loop2: #for j loop
slti t0, s1, 10 #if(j<10)
beq t0, zero, label #if(j>=10) go label
mv t0, s0 # i
mv t1, s1 # j
mul t2, t0, t1 # i*j
mv a1, t0 #else printf i
li a0, 1
ecall
la a1, mul #printf *
li a0, 4
ecall
mv a1, t1 #printf j
li a0, 1
ecall
la a1, equ #printf =
li a0, 4
ecall
mv a1, t2 #printf i*j
li a0, 1
ecall
la a1, spa #printf " "
li a0, 4
ecall
addi s1, s1, 1 #j++
j loop2
label:
la a1, row #printf \n
li a0, 4
ecall
addi s0, s0, 1 #i++
j loop1
exit: #exit
li a0, 10
ecall
```
## Code of testbench
After reading the document [ I-ADD-01](https://github.com/riscv/riscv-compliance/blob/master/riscv-test-suite/rv32i/src/I-ADD-01.S) and [ RISCV-TEST ](https://github.com/riscv/riscv-tests) I found some clue to write the test cases. The test program will begin execution at the first instruction after `RVTEST_CODE_BEGIN`, and continue until execution reaches an `RVTEST_PASS` macro or the `RVTEST_CODE_END` macro, which is implicitly a success. A test can explicitly fail by invoking the `RVTEST_FAIL` macro. `RVTEST_IO_ASSERT_GPR_EQ(x31, x0, 0x00000000):
RVTEST_IO_ASSERT_GPR_EQ(_SP, _R, _I)`: The marco is used to check whther value in `_R` is the same as value specified in `_I`
I want to run this homework with ==rv32i==. But this Instruction Set Architechure is without multiplication. Hence, I rewrite a part of the code above. I rewrite the multiplication in to for loop. For example, if we want to implement 2x5, I divide it into 2 plus 5 times like 2+2+2+2+2. So we can do the multiply without using ==rv32im==.
```c=
#include "compliance_test.h"
#include "compliance_io.h"
#include "test_macros.h"
RV_COMPLIANCE_RV32M
RV_COMPLIANCE_CODE_BEGIN
RVTEST_IO_INIT
RVTEST_IO_ASSERT_GPR_EQ(x31,x0,0x00000000)
RVTEST_IO_WRITE_STR(x31,"#test begin\n")
la x1 , test_res
li x2 , 0 # //i=0
li x4 , 0 # //j=0
main:
addi x2,x2,1 #//i=1
##li x9,100
##sw x9,0(x1)
loop1:
slti x3,x2,10 #//if i < 10
beq x3,zero,exit
addi x4,zero,1
loop2:
slti x3,x4,10 #//if j< 10
beq x3,zero,label
li x9,0
mv x3,x2 #//i mv to x3
mv x5,x4 #//j mv to x5
j loop3
loop5:
addi x4 ,x4,1
j loop2
loop3: //loop for mul
addi x5,x5,1
addi x7,zero,1
loop4:
slt x8,x7,x5
beq x8 ,zero,loop5
add x9 ,x9,x3 # i++ (j)times
addi x7,x7,1
j loop4
label:
addi x2 ,x2,1
j loop1
exit:
sw x9, 0(x1)
RVTEST_IO_CHECK()
RVTEST_IO_ASSERT_GPR_EQ(x1,x9,0x00000051)
RVTEST_IO_WRITE_STR(x31,"#complete~~~~~~~~~~~~~~")
RV_COMPLIANCE_HALT
RV_COMPLIANCE_CODE_END
.data
RV_COMPLIANCE_DATA_BEGIN
.align 4
test_res:
.fill 1,4,-1
RV_COMPLIANCE_DATA_END
```
## Compile .S file to .elf file
* After we finish our .S file, we have to move .S file into src folder in `/home/yuhong/computer_architechure/riscv-compliance/riscv-test-suite/rv32i/src` and also add your .S file name at Makefrag file. And also add your .S file name in the section ==all_test_cases== of the Makefile at`/home/yuhong/computer_architechure/Reindeer/sim/verilator` . Thus it can be sourced when we us "make" instruction.
* OK,Now we can type `make test99.elf` to compile my test99.S to test99.elf.
```
yuhong@gpu2080-System-Product-Name:~/computer_architechure/riscv-compliance/riscv-test-suite/rv32i$ make test99.elf
riscv-none-embed-gcc -march=rv32i -mabi=ilp32 -static -mcmodel=medany -fvisibility=hidden -nostdlib -nostartfiles -I/home/yuhong/computer_architechure/riscv-compliance//riscv-test-env/ -I/home/yuhong/computer_architechure/riscv-compliance//riscv-test-env/p/ -I/home/yuhong/computer_architechure/riscv-compliance/riscv-target/riscvOVPsim/ -T/home/yuhong/computer_architechure/riscv-compliance//riscv-test-env/p/link.ld src/test99.S -o /home/yuhong/computer_architechure/riscv-compliance//work//test99.elf; riscv-none-embed-objdump -D /home/yuhong/computer_architechure/riscv-compliance//work//test99.elf > /home/yuhong/computer_architechure/riscv-compliance//work//test99.elf.objdump
```
## Generate vcd.file from .elf file
* after typing make test99.elf instruction, we will find the elf file and objdump file in `riscv-compliance/work/`
* then we move these two file into
`/home/yuhong/computer_architechure/Reindeer/sim/compliance`
* and go to
`/home/yuhong/computer_architechure/Reindeer/sim/verilator` and type `make test test99` . Then the vcd file of my test99.elf will be produced.
## problem encountered
* When I run my code, it goes wrong at first.

* I check my code with [Ripes](https://github.com/mortbopet/Ripes) from assignment1. And I found that my code is correct. It can run correctly in the Ripes. But it was wrong at this simulator. Below is the screenshot of the result in Ripes.

* After I check the signal in GTKwave, I found the answer. It is because the TOTAL_RUN_CYCLES in tb_PulseRain_RV2T.cpp is only 2000 clocks. But my code needs more than 2000 clocks according to the algorithm. Hence, I change the TOTAL_RUN_CYCLES from 2000 to 10000.

* Finally, the result is correct!

* And I found my code need exactly 8971 clocks because after clock 8971 it start to repeat the same memory space. I guess it means the simulator was idling that time.
## GTKwave
### Checking x2 register
* The way I found the solution of my problem is to trace the gtkwave signal. I found the signal `mem(2)` which indicated the register x2 in my testbench is stop at 00000002. It is wrong because register x2 imply the for loop iteration i.And it should be 1 ~ 9 not stopping at 2.

* Hence, I change the TOTAL_RUN_CYCLES from 2000 to 10000 in order to resovle this problem.

### Checking x4 register
* x4 register means for loop integer j, and its signal wave should be 1~9,1~9,1~9 for 9 times. let's check this signal is like we supposed or not.As I said, its wave is like 1~9 1~9 for 9 times. So it's correct.
### Checking x9 register
* x9 register means my answer about 9*9 mutiplication table and its wave according to my algorithm should be like
>* for i=1: 1 1,2 1,2,3 1,2,3,4 1,2,3,4,5...
>* for i=2: 2 2,4 2,4,6 2,4,6,8 2,4,6,8,10...
>* for i=3: 3 3,6 3,6,9 3,6,9,12 3,6,9,12,15...
* Take i=2,j=2,3,4 for example,the wave should be like 2,4 2,4,6 2,4,6,8. Lets check it out.We can find the signal is waved like I supposed.
## What is “Hold and Load”? and How the simulation does for bootstraping?
In Reindeer soft cpu OCD means on-chip debugger which is used to controll the mux connected to the memory.
In Reindeer soft cpu desing the soft CPU and the OCD can share the same UART port. The RX signal goes to both the soft CPU and OCD, while the TX signal has to go through a mux. And that mux is controlled by the OCD.
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”.
