owned this note
owned this note
Published
Linked with GitHub
# Assigment3: SoftCPU
###### tags: `RISC-V`
## Installation
[Verilator](https://www.veripool.org/wiki/verilator)
```
$ sudo add-apt-repository ppa:iztok.jeras/ppa
$ sudo apt update
$ sudo apt install verilator
```
Check the version
```
$ verilator --version
Verilator 4.028 2020-02-06 rev v4.026-92-g890cecc1
```
GNU Toolchain for RISC-V
```
$source riscv-none-embed-gcc/setenv
```
[GTKWave](http://gtkwave.sourceforge.net/)
```
$ sudo apt install gtkwave
```
[Reindeer](https://github.com/PulseRain/Reindeer)
```
$ git clone https://github.com/PulseRain/Reindeer.git
```
## RISC-V Compliance
According to the [`README.md`](https://github.com/riscv/riscv-compliance), I git clone [imperas-riscv-tests](https://github.com/riscv-ovpsim/imperas-riscv-tests).
> **riscvOVPsim**
> The simulators implement the full and complete functionality of the RISC-V Foundation’s public User and Privilege specifications.
To run the RISCV compliance tests, we need to configure the variable in these `Makefile`.
* configure the toolchain in `~/imperas-riscv-tests/Makefile`
```
export RISCV_DEVICE ?= rv32i
export RISCV_PREFIX ?= riscv-none-embed-
```
* modify `riscv-test-suite/rv32i/Makefile` to ensure it can connect to `Makefile.include`
```
ROOTDIR ?= ~/CA/imperas-riscv-tests
TARGET_DIR := $(ROOTDIR)/riscv-target
RISCV_TARGET := riscvOVPsim
RISCV_DEVICE := rv32i
```
* modify riscvOVPsim in `riscv-target/riscvOVPsim/device/rv32i/Makefile.include`
```
ROOTDIR ?= ~/CA/imperas-riscv-tests
TARGET_SIM ?= $(ROOTDIR)/riscv-ovpsim/bin/$(ARCH)/riscvOVPsim.exe
```
## Rewrite the assembly code
[Bubble Sort](https://hackmd.io/4-oWQOprRnCLu3ZeJy31kA?view)
```c=
#include "compliance_test.h"
#include "compliance_io.h"
#include "test_macros.h"
# Test Virtual Machine
RV_COMPLIANCE_RV32M
# Test code region
RV_COMPLIANCE_CODE_BEGIN
RVTEST_IO_INIT
RVTEST_IO_ASSERT_GPR_EQ(x31, x0, 0x00000000)
RVTEST_IO_WRITE_STR(x31, "Test begin\n")
# load Addresses for test data
la x8, test_data
# test
main:
mv x28, x8
addi x9, x9, 4
addi x5, x0, -1
jal ra, bbsort
addi x5, x0, 0
addi x9, x9, 1
mv x8, x28
j end
bbsort:
addi sp, sp, -12
sw x1, 8(sp)
sw x9, 4(sp)
sw x8, 0(sp)
oloop:
addi x5, x5, 1
mv x6, x0
sub x7, x9, x5
blt x5, x9, iloop
addi sp, sp, 12
jr ra
iloop:
mv x8, x28
bge x6, x7, oloop
slli x29, x6, 2
add x8, x8, x29
lw x12, 0(x8)
lw x13, 4(x8)
addi x6, x6, 1
blt x12, x13, swap
j iloop
swap:
sw x12, 4(x8)
sw x13, 0(x8)
j iloop
end:
la x5, test_res
lw x6, 0(x8)
sw x6, 0(x5)
lw x6, 4(x8)
sw x6, 4(x5)
lw x6, 8(x8)
sw x6, 8(x5)
lw x6, 12(x8)
sw x6, 12(x5)
RVTEST_IO_WRITE_STR(x31, "Test End\n")
# HALT
RV_COMPLIANCE_HALT
RV_COMPLIANCE_CODE_END
# Input data section.
.align 4
test_data:
.word 2, 3, 7, 4
# Output data section.
RV_COMPLIANCE_DATA_BEGIN
test_res:
.fill 4, 4, -1
RV_COMPLIANCE_DATA_END
```
* Add the `.S` to `riscv-test-suite/rv32i/src`, `riscv-test-suite/rv32i/Makefrag`
* Generate the `.elf`
```
make RISCV_TEST='BUBBLE'
```
```
work
└── rv32i
├── BUBBLE.basic.coverage.yaml
├── BUBBLE.elf
├── BUBBLE.elf.objdump
├── BUBBLE.log
└── BUBBLE.signature.output
```
* Check the signature
2, 3, 7, 4 -> 7, 4, 3, 2
```
00000007
00000004
00000003
00000002
```
### GTKWave
* Copy `.elf`, `.objdump`, `.signature.output` from `./work` to `Reindeer/sim/compliance`
* Start the simulation `make test BUBBLE`
```c=
...
=============================================================
Simulation exit ../compliance/BUBBLE.elf
Wave trace BUBBLE.vcd
=============================================================
====> Test PASSED, Total of 1 case(s)
```
#### waveform
```c
...
80000108 <begin_testcode>:
80000108: 00000417 auipc s0,0x0
8000010c: 0b840413 addi s0,s0,184 # 800001c0 <test_data>
80000110 <main>:
80000110: 00040e13 mv t3,s0
80000114: 00448493 addi s1,s1,4
80000118: fff00293 li t0,-1
...
```

The test suite start at `80000108`
```c
...
80000188 <end>:
80000188: 00000297 auipc t0,0x0
8000018c: 04828293 addi t0,t0,72 # 800001d0 <begin_signature>
80000190: 00042303 lw t1,0(s0) # 7
80000194: 0062a023 sw t1,0(t0)
80000198: 00442303 lw t1,4(s0) # 4
8000019c: 0062a223 sw t1,4(t0)
800001a0: 00842303 lw t1,8(s0)
...
```

I load the result form `s0`, and store in `t1`.
We can see that the data at `80000194` is `7` which, and the data at `80000198` is `4`.
## How Reindeer works with Verilator
[Reindeer]() is a soft CPU of Von Neumann architecture.
Verilator can convert verilog to a cycle-accurate behavioral model in C++ or SystemC. The generated models are cycle-accurate, 2-state.
## What is 2 x 2 Pipeline? How can we benefit from such pipeline design?

Each stage of 2X2 pipeline is active every other clock cycle in Reindeer.
IF, IE are on the even cycles.
ID, MEM are on the odd cycles.
To avoid stuctural hazard, IF and MEM is on different clock cycles in this way.
> Strctural hazard: a required source is busy
## What is “Hold and Load”?
Bring a hardware based OCD(on-chip debugger) into the fore

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".
## Simulation does for bootstraping?
TBD